From ce4e5258e704ab01af2bdb44a0283257a938a8c3 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 23 Nov 2025 23:49:34 +0200 Subject: [PATCH 01/15] `stream_identifier()` with an index sequence needs to be available --- dev/serializing_util.h | 12 ++++++------ include/sqlite_orm/sqlite_orm.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 080519ca..dbc4d8ee 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -81,6 +81,12 @@ namespace sqlite_orm { return stream_identifier(ss, "", identifier, ""); } + template + void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { + static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); + return stream_identifier(ss, std::get(tpl)...); + } + #ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED template requires polyfill::is_detected_v> @@ -90,12 +96,6 @@ namespace sqlite_orm { return stream_identifier(ss, elements...); } #else - template - void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { - static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); - return stream_identifier(ss, std::get(tpl)...); - } - template>::value, bool> = true> void stream_identifier(std::ostream& ss, const Tpl& tpl) { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 5b81e6de..45b0e891 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -17446,6 +17446,12 @@ namespace sqlite_orm { return stream_identifier(ss, "", identifier, ""); } + template + void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { + static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); + return stream_identifier(ss, std::get(tpl)...); + } + #ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED template requires polyfill::is_detected_v> @@ -17455,12 +17461,6 @@ namespace sqlite_orm { return stream_identifier(ss, elements...); } #else - template - void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { - static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); - return stream_identifier(ss, std::get(tpl)...); - } - template>::value, bool> = true> void stream_identifier(std::ostream& ss, const Tpl& tpl) { From 1f4be689b2a82765ed246795228369f899032197 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Sun, 23 Nov 2025 23:56:05 +0200 Subject: [PATCH 02/15] Used the single-argument version of `static_assert` --- dev/alias.h | 2 +- dev/functional/cxx_check_prerequisites.h | 2 +- dev/serializing_util.h | 2 +- dev/statement_serializer.h | 2 +- include/sqlite_orm/sqlite_orm.h | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index e43d7d38..57f86787 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -379,7 +379,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { */ template internal::alias_holder get() { - static_assert(internal::is_column_alias_v, ""); + static_assert(internal::is_column_alias_v); return {}; } diff --git a/dev/functional/cxx_check_prerequisites.h b/dev/functional/cxx_check_prerequisites.h index 20ed286f..224364d8 100644 --- a/dev/functional/cxx_check_prerequisites.h +++ b/dev/functional/cxx_check_prerequisites.h @@ -11,7 +11,7 @@ #endif #if (!defined(__has_include)) || \ - ((__cpp_noexcept_function_type < 201510L) || \ + ((__cpp_static_assert < 201411L) || (__cpp_noexcept_function_type < 201510L) || \ (__cpp_fold_expressions < 201603L || __cpp_constexpr < 201603L || __cpp_aggregate_bases < 201603L || \ __cpp_range_based_for < 201603L) || \ (__cpp_if_constexpr < 201606L || __cpp_inline_variables < 201606L || __cpp_structured_bindings < 201606L) || \ diff --git a/dev/serializing_util.h b/dev/serializing_util.h index dbc4d8ee..9990b8ac 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -83,7 +83,7 @@ namespace sqlite_orm { template void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { - static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); + static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3); return stream_identifier(ss, std::get(tpl)...); } diff --git a/dev/statement_serializer.h b/dev/statement_serializer.h index 0409305b..f9349124 100644 --- a/dev/statement_serializer.h +++ b/dev/statement_serializer.h @@ -101,7 +101,7 @@ namespace sqlite_orm { , bool> = true> static std::string do_serialize(const X& c) { - static_assert(std::is_same::value, ""); + static_assert(std::is_same::value); // implementation detail: utilizing field_printer return field_printer{}(c); diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 45b0e891..bb87cb3b 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -51,7 +51,7 @@ using std::nullptr_t; #endif #if (!defined(__has_include)) || \ - ((__cpp_noexcept_function_type < 201510L) || \ + ((__cpp_static_assert < 201411L) || (__cpp_noexcept_function_type < 201510L) || \ (__cpp_fold_expressions < 201603L || __cpp_constexpr < 201603L || __cpp_aggregate_bases < 201603L || \ __cpp_range_based_for < 201603L) || \ (__cpp_if_constexpr < 201606L || __cpp_inline_variables < 201606L || __cpp_structured_bindings < 201606L) || \ @@ -2960,7 +2960,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { */ template internal::alias_holder get() { - static_assert(internal::is_column_alias_v, ""); + static_assert(internal::is_column_alias_v); return {}; } @@ -17448,7 +17448,7 @@ namespace sqlite_orm { template void stream_identifier(std::ostream& ss, const Tpl& tpl, std::index_sequence) { - static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3, ""); + static_assert(sizeof...(Is) > 0 && sizeof...(Is) <= 3); return stream_identifier(ss, std::get(tpl)...); } @@ -21150,7 +21150,7 @@ namespace sqlite_orm { , bool> = true> static std::string do_serialize(const X& c) { - static_assert(std::is_same::value, ""); + static_assert(std::is_same::value); // implementation detail: utilizing field_printer return field_printer{}(c); From c260842d207a5522c02d80e1b660d39fecb10801 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 24 Nov 2025 00:22:22 +0200 Subject: [PATCH 03/15] Accommodated for Clang on Windows, which cannot use constexpr DLL exports --- dev/functional/cxx_compiler_quirks.h | 5 ++++- dev/prepared_statement.h | 10 ++++++++++ dev/statement_finalizer.h | 14 ++++++++++++++ include/sqlite_orm/sqlite_orm.h | 29 +++++++++++++++++++++++++++- tests/xdestroy_handling.cpp | 6 ++++++ 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 14e0b05d..c6043bbf 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -15,7 +15,6 @@ SQLITE_ORM_DO_PRAGMA(clang diagnostic ignored warnoption) \ __VA_ARGS__ \ SQLITE_ORM_DO_PRAGMA(clang diagnostic pop) - #else #define SQLITE_ORM_CLANG_SUPPRESS(warnoption, ...) __VA_ARGS__ #endif @@ -30,6 +29,10 @@ #define SQLITE_ORM_MSVC_SUPPRESS(warcode, ...) __VA_ARGS__ #endif +#if defined(_MSC_VER) && defined(__clang__) +#define SQLITE_ORM_CLANG_ON_WIN +#endif + // clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. // This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, // see https://en.cppreference.com/w/cpp/language/aggregate_initialization: diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index d5a6bc98..7bbed6cf 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -47,7 +47,17 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3014000 std::string expanded_sql() const { // note: must check return value due to SQLITE_OMIT_TRACE +#ifndef SQLITE_ORM_CLANG_ON_WIN using char_ptr = std::unique_ptr>; +#else + struct sqlite3_memory_deleter { + SQLITE_ORM_STATIC_CALLOP void operator()(void* mem) SQLITE_ORM_OR_CONST_CALLOP noexcept { + sqlite3_free(mem); + } + }; + using char_ptr = std::unique_ptr; +#endif + if (char_ptr sql{sqlite3_expanded_sql(this->stmt)}) { return sql.get(); } else { diff --git a/dev/statement_finalizer.h b/dev/statement_finalizer.h index 1de4575f..73b67d29 100644 --- a/dev/statement_finalizer.h +++ b/dev/statement_finalizer.h @@ -6,11 +6,25 @@ #include // std::integral_constant #endif +#ifdef SQLITE_ORM_CLANG_ON_WIN +namespace sqlite_orm::internal { + struct statement_deleter { + SQLITE_ORM_STATIC_CALLOP void operator()(sqlite3_stmt* stmt) SQLITE_ORM_OR_CONST_CALLOP noexcept { + sqlite3_finalize(stmt); + } + }; +} +#endif + SQLITE_ORM_EXPORT namespace sqlite_orm { +#ifndef SQLITE_ORM_CLANG_ON_WIN /** * Guard class which finalizes `sqlite3_stmt` in dtor */ using statement_finalizer = std::unique_ptr>; +#else + using statement_finalizer = std::unique_ptr; +#endif } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index bb87cb3b..935f1797 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -150,7 +150,6 @@ using std::nullptr_t; SQLITE_ORM_DO_PRAGMA(clang diagnostic ignored warnoption) \ __VA_ARGS__ \ SQLITE_ORM_DO_PRAGMA(clang diagnostic pop) - #else #define SQLITE_ORM_CLANG_SUPPRESS(warnoption, ...) __VA_ARGS__ #endif @@ -165,6 +164,10 @@ using std::nullptr_t; #define SQLITE_ORM_MSVC_SUPPRESS(warcode, ...) __VA_ARGS__ #endif +#if defined(_MSC_VER) && defined(__clang__) +#define SQLITE_ORM_CLANG_ON_WIN +#endif + // clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. // This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, // see https://en.cppreference.com/w/cpp/language/aggregate_initialization: @@ -14008,13 +14011,27 @@ namespace sqlite_orm { #include // std::integral_constant #endif +#ifdef SQLITE_ORM_CLANG_ON_WIN +namespace sqlite_orm::internal { + struct statement_deleter { + SQLITE_ORM_STATIC_CALLOP void operator()(sqlite3_stmt* stmt) SQLITE_ORM_OR_CONST_CALLOP noexcept { + sqlite3_finalize(stmt); + } + }; +} +#endif + SQLITE_ORM_EXPORT namespace sqlite_orm { +#ifndef SQLITE_ORM_CLANG_ON_WIN /** * Guard class which finalizes `sqlite3_stmt` in dtor */ using statement_finalizer = std::unique_ptr>; +#else + using statement_finalizer = std::unique_ptr; +#endif } // #include "error_code.h" @@ -15310,7 +15327,17 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3014000 std::string expanded_sql() const { // note: must check return value due to SQLITE_OMIT_TRACE +#ifndef SQLITE_ORM_CLANG_ON_WIN using char_ptr = std::unique_ptr>; +#else + struct sqlite3_memory_deleter { + SQLITE_ORM_STATIC_CALLOP void operator()(void* mem) SQLITE_ORM_OR_CONST_CALLOP noexcept { + sqlite3_free(mem); + } + }; + using char_ptr = std::unique_ptr; +#endif + if (char_ptr sql{sqlite3_expanded_sql(this->stmt)}) { return sql.get(); } else { diff --git a/tests/xdestroy_handling.cpp b/tests/xdestroy_handling.cpp index 93503abf..68dbe5a9 100644 --- a/tests/xdestroy_handling.cpp +++ b/tests/xdestroy_handling.cpp @@ -23,8 +23,10 @@ template inline constexpr delete_default_t delete_default_f{}; #endif +#ifndef SQLITE_ORM_CLANG_ON_WIN using free_t = std::integral_constant; inline constexpr free_t free_f{}; +#endif TEST_CASE("obtain_xdestroy_for") { @@ -62,6 +64,7 @@ TEST_CASE("obtain_xdestroy_for") { STATIC_REQUIRE(xDestroy1 == nullptr); REQUIRE(xDestroy1 == nullptr); +#ifndef SQLITE_ORM_CLANG_ON_WIN // free(int*) constexpr xdestroy_fn_t xDestroy2 = obtain_xdestroy_for(free, int_nullptr); STATIC_REQUIRE(xDestroy2 == &free); @@ -71,6 +74,7 @@ TEST_CASE("obtain_xdestroy_for") { constexpr xdestroy_fn_t xDestroy3 = obtain_xdestroy_for(free_f, int_nullptr); STATIC_REQUIRE(xDestroy3 == &free); REQUIRE(xDestroy3 == &free); +#endif #if __cpp_constexpr >= 201603L // constexpr lambda // [](void* p){} @@ -116,6 +120,7 @@ TEST_CASE("obtain_xdestroy_for") { #endif #if __cpp_constexpr >= 201907L // Trivial default initialization in constexpr functions +#ifndef SQLITE_ORM_CLANG_ON_WIN // xdestroy_holder{ free }(int*) constexpr xdestroy_fn_t xDestroy8 = obtain_xdestroy_for(xdestroy_holder{free}, int_nullptr); STATIC_REQUIRE(xDestroy8 == &free); @@ -130,6 +135,7 @@ TEST_CASE("obtain_xdestroy_for") { constexpr xdestroy_fn_t xDestroy10 = obtain_xdestroy_for(xdestroy_holder{nullptr}, const_int_nullptr); STATIC_REQUIRE(xDestroy10 == nullptr); REQUIRE(xDestroy10 == nullptr); +#endif #endif // expressions that do not work From c39d2f88094ab2ac6e76c6915309464ae4f196c5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 24 Nov 2025 10:41:16 +0200 Subject: [PATCH 04/15] Updated to clang-format 20 --- .clang-format | 2 +- .github/workflows/clang-format-lint.yaml | 4 ++-- dev/cte_column_names_collector.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- tests/user_defined_functions.cpp | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.clang-format b/.clang-format index 558c0d0a..4d064552 100644 --- a/.clang-format +++ b/.clang-format @@ -1,5 +1,6 @@ --- Language: Cpp +Standard: Latest AccessModifierOffset: -2 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false @@ -117,7 +118,6 @@ SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 AttributeMacros: [SQLITE_ORM_CPP_LIKELY, SQLITE_ORM_CPP_UNLIKELY, SQLITE_ORM_EXPORT] StatementMacros: - __pragma diff --git a/.github/workflows/clang-format-lint.yaml b/.github/workflows/clang-format-lint.yaml index 65f06004..dce93991 100644 --- a/.github/workflows/clang-format-lint.yaml +++ b/.github/workflows/clang-format-lint.yaml @@ -9,6 +9,6 @@ jobs: steps: - uses: actions/checkout@v1 - name: clang-format lint - uses: d-griet/clang-format-lint-action@99a106be2f3f1a92d9783ea7c744fde62d8ce1fa + uses: DoozyX/clang-format-lint-action@8b8bbdd8669eec54682e720ebe2fb19d9387fdb0 with: - clangFormatVersion: 19 + clangFormatVersion: 20 diff --git a/dev/cte_column_names_collector.h b/dev/cte_column_names_collector.h index b02fbf20..106d547b 100644 --- a/dev/cte_column_names_collector.h +++ b/dev/cte_column_names_collector.h @@ -204,7 +204,7 @@ namespace sqlite_orm { // 3. fill in blanks with numerical column identifiers { #ifdef SQLITE_ORM_INITSTMT_RANGE_BASED_FOR_SUPPORTED - for (size_t n = 1; std::string & name: columnNames) { + for (size_t n = 1; std::string& name: columnNames) { if (name.empty()) { name = std::to_string(n); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 935f1797..c92fba5a 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -20571,7 +20571,7 @@ namespace sqlite_orm { // 3. fill in blanks with numerical column identifiers { #ifdef SQLITE_ORM_INITSTMT_RANGE_BASED_FOR_SUPPORTED - for (size_t n = 1; std::string & name: columnNames) { + for (size_t n = 1; std::string& name: columnNames) { if (name.empty()) { name = std::to_string(n); } diff --git a/tests/user_defined_functions.cpp b/tests/user_defined_functions.cpp index c54a0b01..67d25abb 100644 --- a/tests/user_defined_functions.cpp +++ b/tests/user_defined_functions.cpp @@ -200,8 +200,8 @@ struct SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(alignas(2 * __STDCPP_DEFAULT_NEW_A } }; -struct SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(alignas(2 * - __STDCPP_DEFAULT_NEW_ALIGNMENT__)) OverAlignedAggregateFunction { +struct SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(alignas(2 * __STDCPP_DEFAULT_NEW_ALIGNMENT__)) + OverAlignedAggregateFunction { double sum = 0; void step(double arg) { From f6e12ba6c2bdd5af0de6cebc3b54056455880cca Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 24 Nov 2025 11:07:01 +0200 Subject: [PATCH 05/15] Space in user-defined literal operator is deprecated --- dev/alias.h | 6 +++--- dev/cte_moniker.h | 4 ++-- dev/function.h | 2 +- dev/pointer_value.h | 2 +- include/sqlite_orm/sqlite_orm.h | 14 +++++++------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dev/alias.h b/dev/alias.h index 57f86787..007f9c5c 100644 --- a/dev/alias.h +++ b/dev/alias.h @@ -469,7 +469,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * constexpr orm_table_alias auto z_alias = "z"_alias.for_(); */ template - [[nodiscard]] consteval auto operator"" _alias() { + [[nodiscard]] consteval auto operator""_alias() { return internal::explode_into( std::make_index_sequence{}); } @@ -479,7 +479,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. "a"_col, "b"_col */ template - [[nodiscard]] consteval auto operator"" _col() { + [[nodiscard]] consteval auto operator""_col() { return internal::explode_into(std::make_index_sequence{}); } } @@ -492,7 +492,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. 1_colalias, 2_colalias */ template - [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _colalias() { + [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator""_colalias() { // numeric identifiers are used for automatically assigning implicit aliases to unaliased column expressions, // which start at "1". static_assert(std::array{Chars...}[0] > '0'); diff --git a/dev/cte_moniker.h b/dev/cte_moniker.h index e723b02d..a53417cf 100644 --- a/dev/cte_moniker.h +++ b/dev/cte_moniker.h @@ -76,7 +76,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. 1_ctealias, 2_ctealias */ template - [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _ctealias() { + [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator""_ctealias() { return internal::cte_moniker{}; } @@ -86,7 +86,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. "1"_cte, "2"_cte */ template - [[nodiscard]] consteval auto operator"" _cte() { + [[nodiscard]] consteval auto operator""_cte() { return internal::explode_into(std::make_index_sequence{}); } #endif diff --git a/dev/function.h b/dev/function.h index a7660179..542a5348 100644 --- a/dev/function.h +++ b/dev/function.h @@ -580,7 +580,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * auto rows = storage.select(equal_to_int_3_f(1, 1)); */ template - [[nodiscard]] consteval auto operator"" _scalar() { + [[nodiscard]] consteval auto operator""_scalar() { return builder; } } diff --git a/dev/pointer_value.h b/dev/pointer_value.h index 4727f4ae..d5cfa3d2 100644 --- a/dev/pointer_value.h +++ b/dev/pointer_value.h @@ -32,7 +32,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { #ifdef SQLITE_ORM_WITH_CPP20_ALIASES inline namespace literals { template - [[nodiscard]] consteval auto operator"" _pointer_type() { + [[nodiscard]] consteval auto operator""_pointer_type() { return internal::explode_into(std::make_index_sequence{}); } } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index c92fba5a..d510c88e 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -3053,7 +3053,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * constexpr orm_table_alias auto z_alias = "z"_alias.for_(); */ template - [[nodiscard]] consteval auto operator"" _alias() { + [[nodiscard]] consteval auto operator""_alias() { return internal::explode_into( std::make_index_sequence{}); } @@ -3063,7 +3063,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. "a"_col, "b"_col */ template - [[nodiscard]] consteval auto operator"" _col() { + [[nodiscard]] consteval auto operator""_col() { return internal::explode_into(std::make_index_sequence{}); } } @@ -3076,7 +3076,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. 1_colalias, 2_colalias */ template - [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _colalias() { + [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator""_colalias() { // numeric identifiers are used for automatically assigning implicit aliases to unaliased column expressions, // which start at "1". static_assert(std::array{Chars...}[0] > '0'); @@ -8878,7 +8878,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. 1_ctealias, 2_ctealias */ template - [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator"" _ctealias() { + [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator""_ctealias() { return internal::cte_moniker{}; } @@ -8888,7 +8888,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * E.g. "1"_cte, "2"_cte */ template - [[nodiscard]] consteval auto operator"" _cte() { + [[nodiscard]] consteval auto operator""_cte() { return internal::explode_into(std::make_index_sequence{}); } #endif @@ -10337,7 +10337,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { #ifdef SQLITE_ORM_WITH_CPP20_ALIASES inline namespace literals { template - [[nodiscard]] consteval auto operator"" _pointer_type() { + [[nodiscard]] consteval auto operator""_pointer_type() { return internal::explode_into(std::make_index_sequence{}); } } @@ -12063,7 +12063,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { * auto rows = storage.select(equal_to_int_3_f(1, 1)); */ template - [[nodiscard]] consteval auto operator"" _scalar() { + [[nodiscard]] consteval auto operator""_scalar() { return builder; } } From f20f33f106735c878f5becfbdbe12489c53456e3 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 24 Nov 2025 17:34:17 +0200 Subject: [PATCH 06/15] Updated and improved code after compiling with Clang MSVC v21 and C++26 * Temporarily disable spurious Clang warnings instead of suppressing them in code. * Clang understands C++26 even in C++17 mode, but it doesn't mean it understands other language features, so we need to be specific using them. * Removed a few unused type aliases in UTs. * Addressed a few warnings about unused variables. * Needed to disable the rtree module example because Clang chokes on using constexpr variables in lambdas. --- CMakeLists.txt | 2 +- dev/cte_storage.h | 3 +- dev/functional/cxx_compiler_quirks.h | 14 +-- dev/functional/start_macros.h | 12 +- dev/prepared_statement.h | 2 +- dev/schema/column.h | 12 +- dev/schema/index.h | 9 +- dev/schema/table.h | 6 +- dev/schema/triggers.h | 3 +- dev/schema/virtual_table.h | 4 +- dev/serializing_util.h | 2 +- dev/statement_binder.h | 9 +- dev/statement_finalizer.h | 4 +- dev/storage.h | 2 +- dev/table_reference.h | 6 +- dev/tuple_helper/tuple_transformer.h | 4 +- dev/util.h | 4 +- dev/vtabs/dbstat.h | 2 +- dev/vtabs/fts5.h | 6 +- dev/vtabs/generate_series.h | 2 +- dev/vtabs/rtree.h | 4 +- examples/rtree.cpp | 3 +- include/sqlite_orm/sqlite_orm.h | 110 ++++++++---------- tests/CMakeLists.txt | 11 +- .../static_tests/functional/tuple_traits.cpp | 1 - tests/static_tests/virtual_tables.cpp | 1 - tests/xdestroy_handling.cpp | 6 +- 27 files changed, 116 insertions(+), 128 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e091b46f..9124ea2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_VERBOSE_MAKEFILE ON) -message(STATUS "Configuring ${PROJECT_NAME} ${sqlite_orm_VERSION}") +message(STATUS "Configuring ${PROJECT_NAME} ${sqlite_orm_VERSION} for ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") diff --git a/dev/cte_storage.h b/dev/cte_storage.h index 8f609527..d0511b0b 100644 --- a/dev/cte_storage.h +++ b/dev/cte_storage.h @@ -75,8 +75,7 @@ namespace sqlite_orm { template cte_table make_cte_table(std::string name, Cs... args) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(args)...)}); + return {std::move(name), std::make_tuple(std::forward(args)...)}; } // aliased column expressions, explicit or implicitly numbered diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index c6043bbf..52466e3a 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -26,23 +26,13 @@ #if defined(_MSC_VER) && !defined(__clang__) #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) SQLITE_ORM_DO_PRAGMA(warning(suppress : warncode)) #else -#define SQLITE_ORM_MSVC_SUPPRESS(warcode, ...) __VA_ARGS__ +#define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ #endif #if defined(_MSC_VER) && defined(__clang__) -#define SQLITE_ORM_CLANG_ON_WIN +#define SQLITE_ORM_CLANG_MSVC #endif -// clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. -// This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, -// see https://en.cppreference.com/w/cpp/language/aggregate_initialization: -// "The braces around the nested initializer lists may be elided (omitted), -// in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, -// and the subsequent initializer clauses are used to initialize the following members of the object." -// In this sense clang should only warn about missing field initializers. -// Because we know what we are doing, we suppress the diagnostic message -#define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) - // msvc has the bad habit of diagnosing overalignment of types with an explicit alignment specifier. #define SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(...) SQLITE_ORM_MSVC_SUPPRESS(4324, __VA_ARGS__) diff --git a/dev/functional/start_macros.h b/dev/functional/start_macros.h index 7ec4f643..f5d7e625 100644 --- a/dev/functional/start_macros.h +++ b/dev/functional/start_macros.h @@ -1,11 +1,21 @@ #pragma once -// Clang has the annoying habit of warning about future C++ features that it claims to support through a feature macro. #ifdef __clang__ #pragma clang diagnostic push +// Clang has the annoying habit of warning about future C++ features that it claims to support through a feature macro. #pragma clang diagnostic ignored "-Wc++20-extensions" #pragma clang diagnostic ignored "-Wc++23-extensions" #pragma clang diagnostic ignored "-Wc++26-extensions" + +// clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. +// This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, +// see https://en.cppreference.com/w/cpp/language/aggregate_initialization: +// "The braces around the nested initializer lists may be elided (omitted), +// in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, +// and the subsequent initializer clauses are used to initialize the following members of the object." +// In this sense clang should only warn about missing field initializers. +// Because we know what we are doing, we suppress the diagnostic message +#pragma clang diagnostic ignored "-Wmissing-braces" #endif #if defined(_MSC_VER) diff --git a/dev/prepared_statement.h b/dev/prepared_statement.h index 7bbed6cf..e2909bfc 100644 --- a/dev/prepared_statement.h +++ b/dev/prepared_statement.h @@ -47,7 +47,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3014000 std::string expanded_sql() const { // note: must check return value due to SQLITE_OMIT_TRACE -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC using char_ptr = std::unique_ptr>; #else struct sqlite3_memory_deleter { diff --git a/dev/schema/column.h b/dev/schema/column.h index 35e05949..62e0dad6 100644 --- a/dev/schema/column.h +++ b/dev/schema/column.h @@ -175,8 +175,7 @@ namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}); + return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}; } #endif } @@ -193,8 +192,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}); + return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}; } /** @@ -212,8 +210,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}); + return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}; } /** @@ -231,7 +228,6 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}); + return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}; } } diff --git a/dev/schema/index.h b/dev/schema/index.h index b6bc9271..00f17b58 100644 --- a/dev/schema/index.h +++ b/dev/schema/index.h @@ -37,8 +37,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}; } template @@ -48,8 +47,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}; } template @@ -59,7 +57,6 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}; } } diff --git a/dev/schema/table.h b/dev/schema/table.h index c6b7bb6c..9d97e396 100644 --- a/dev/schema/table.h +++ b/dev/schema/table.h @@ -131,8 +131,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { static_assert(polyfill::conjunction_v...>, "Incorrect table elements or constraints"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(definition)...)}); + return {std::move(name), std::make_tuple(std::forward(definition)...)}; } /** @@ -145,8 +144,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { static_assert(polyfill::conjunction_v...>, "Incorrect table elements or constraints"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(definition)...)}); + return {std::move(name), std::make_tuple(std::forward(definition)...)}; } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES diff --git a/dev/schema/triggers.h b/dev/schema/triggers.h index 0ceb4738..0bf79e81 100644 --- a/dev/schema/triggers.h +++ b/dev/schema/triggers.h @@ -265,8 +265,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { template internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::move(part.base), std::move(part.statements)}); + return {std::move(name), std::move(part.base), std::move(part.statements)}; } inline internal::trigger_timing_t before() { diff --git a/dev/schema/virtual_table.h b/dev/schema/virtual_table.h index dbf6dbf4..8a7a57f4 100644 --- a/dev/schema/virtual_table.h +++ b/dev/schema/virtual_table.h @@ -113,7 +113,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { template internal::virtual_table make_virtual_table(std::string name, internal::virtual_table_description description) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(description)}); + return {std::move(name), std::move(description)}; } /** @@ -124,7 +124,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { template internal::virtual_table make_virtual_table(std::string name, internal::virtual_table_definition definition) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(definition)}); + return {std::move(name), std::move(definition)}; } /** diff --git a/dev/serializing_util.h b/dev/serializing_util.h index 9990b8ac..52c9459c 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -87,7 +87,7 @@ namespace sqlite_orm { return stream_identifier(ss, std::get(tpl)...); } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED +#if defined(SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED) && defined(SQLITE_ORM_CONCEPTS_SUPPORTED) template requires polyfill::is_detected_v> void stream_identifier(std::ostream& ss, const Tpl& tpl) { diff --git a/dev/statement_binder.h b/dev/statement_binder.h index 0ea57f03..51189b7c 100644 --- a/dev/statement_binder.h +++ b/dev/statement_binder.h @@ -298,7 +298,7 @@ namespace sqlite_orm { template = true> void operator()(const T& t) { - int rc = statement_binder{}.bind(this->stmt, ++this->nthSqlParameter, t); + const int rc = statement_binder{}.bind(this->stmt, ++this->nthSqlParameter, t); if (SQLITE_OK != rc) SQLITE_ORM_CPP_UNLIKELY /*possible but unexpected*/ { throw_translated_sqlite_error(rc); } @@ -330,10 +330,11 @@ namespace sqlite_orm { explicit tuple_value_binder(sqlite3_stmt* stmt) : stmt{stmt} {} #ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED - void operator()(const auto& tpl, auto project) const { + template + void operator()(const Tpl& tpl, Projection project) const { int nthSqlParameter = 0; auto& [... elements] = tpl; - (this->bind(std::invoke(project, elements), ++nthSqlParameter), ...); + (this->bind(polyfill::invoke(project, elements), ++nthSqlParameter), ...); } #else template @@ -354,7 +355,7 @@ namespace sqlite_orm { template void bind(const T& t, int nthSqlParameter) const { - int rc = statement_binder{}.bind(this->stmt, nthSqlParameter, t); + const int rc = statement_binder{}.bind(this->stmt, nthSqlParameter, t); if (SQLITE_OK != rc) SQLITE_ORM_CPP_UNLIKELY /*possible but unexpected*/ { throw_translated_sqlite_error(rc); } diff --git a/dev/statement_finalizer.h b/dev/statement_finalizer.h index 73b67d29..9f9d9257 100644 --- a/dev/statement_finalizer.h +++ b/dev/statement_finalizer.h @@ -6,7 +6,7 @@ #include // std::integral_constant #endif -#ifdef SQLITE_ORM_CLANG_ON_WIN +#ifdef SQLITE_ORM_CLANG_MSVC namespace sqlite_orm::internal { struct statement_deleter { SQLITE_ORM_STATIC_CALLOP void operator()(sqlite3_stmt* stmt) SQLITE_ORM_OR_CONST_CALLOP noexcept { @@ -18,7 +18,7 @@ namespace sqlite_orm::internal { SQLITE_ORM_EXPORT namespace sqlite_orm { -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC /** * Guard class which finalizes `sqlite3_stmt` in dtor */ diff --git a/dev/storage.h b/dev/storage.h index 4f0c63bc..613935be 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -1656,7 +1656,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch (int rc = sqlite3_step(stmt)) { + switch (/*int rc =*/sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { diff --git a/dev/table_reference.h b/dev/table_reference.h index 7819d1ff..728df490 100644 --- a/dev/table_reference.h +++ b/dev/table_reference.h @@ -38,7 +38,8 @@ namespace sqlite_orm::internal { * Make a table-valued function call. */ template - constexpr table_valued_expression operator()(Args... arguments) const { + constexpr SQLITE_ORM_STATIC_CALLOP table_valued_expression + operator()(Args... arguments) SQLITE_ORM_OR_CONST_CALLOP { return {{ {std::move(arguments)}... }}; } #else @@ -46,7 +47,8 @@ namespace sqlite_orm::internal { * Make a table-valued function call. */ template - constexpr table_valued_expression operator()(Args... arguments) const { + constexpr SQLITE_ORM_STATIC_CALLOP table_valued_expression + operator()(Args... arguments) SQLITE_ORM_OR_CONST_CALLOP { return {{{std::move(arguments)}...}}; } #endif diff --git a/dev/tuple_helper/tuple_transformer.h b/dev/tuple_helper/tuple_transformer.h index 8a715758..f3d6d0ed 100644 --- a/dev/tuple_helper/tuple_transformer.h +++ b/dev/tuple_helper/tuple_transformer.h @@ -100,7 +100,7 @@ namespace sqlite_orm { return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED +#if defined(SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED) && __cpp_lib_forward_like >= 202207L /* * Like `std::make_from_tuple()`, but using a projection on the tuple elements. */ @@ -127,7 +127,7 @@ namespace sqlite_orm { return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED +#if defined(SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED) && __cpp_lib_forward_like >= 202207L /* * Similar to `create_from_tuple()`, but the result type is specified as a class template. */ diff --git a/dev/util.h b/dev/util.h index 1b88f589..8d408f6e 100644 --- a/dev/util.h +++ b/dev/util.h @@ -81,7 +81,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch (int rc = sqlite3_step(stmt)) { + switch (/*int rc =*/sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -97,7 +97,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch (int rc = sqlite3_step(stmt)) { + switch (/*int rc =*/sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; diff --git a/dev/vtabs/dbstat.h b/dev/vtabs/dbstat.h index bcc9b0b5..6e35a2f3 100644 --- a/dev/vtabs/dbstat.h +++ b/dev/vtabs/dbstat.h @@ -44,7 +44,7 @@ namespace sqlite_orm::internal { template inline virtual_table_definition make_dbstat_definition(Cs... columns) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {{std::make_tuple(std::move(columns)...)}}); + return {{std::make_tuple(std::move(columns)...)}}; } } diff --git a/dev/vtabs/fts5.h b/dev/vtabs/fts5.h index 1857c939..190ac96c 100644 --- a/dev/vtabs/fts5.h +++ b/dev/vtabs/fts5.h @@ -38,7 +38,7 @@ namespace sqlite_orm::internal { template inline virtual_table_definition make_fts5_definition(Cs... definition) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {{std::make_tuple(std::move(definition)...)}}); + return {{std::make_tuple(std::move(definition)...)}}; } } @@ -121,7 +121,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { static_assert((internal::is_fts5_table_element_or_constraint_v && ...), "Incorrect table elements or constraints"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(definition)...)}); + return {std::make_tuple(std::forward(definition)...)}; } template @@ -137,7 +137,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { std::get(definition.elements).name = tableName; #endif - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(tableName), std::move(definition)}); + return {std::move(tableName), std::move(definition)}; } } #endif diff --git a/dev/vtabs/generate_series.h b/dev/vtabs/generate_series.h index b8d4f040..cfddc3aa 100644 --- a/dev/vtabs/generate_series.h +++ b/dev/vtabs/generate_series.h @@ -40,7 +40,7 @@ namespace sqlite_orm::internal { template inline virtual_table_definition make_generate_series_definition(Cs... columns) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {{std::make_tuple(std::move(columns)...)}}); + return {{std::make_tuple(std::move(columns)...)}}; } } diff --git a/dev/vtabs/rtree.h b/dev/vtabs/rtree.h index 01093660..52f4d5b6 100644 --- a/dev/vtabs/rtree.h +++ b/dev/vtabs/rtree.h @@ -70,7 +70,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { internal::virtual_table_definition using_rtree(Cs... definition) { internal::validate_rtree_definition(); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(definition)...)}); + return {std::make_tuple(std::forward(definition)...)}; } /** * Factory function for a RTREE_I32 virtual table definition. @@ -79,7 +79,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { internal::virtual_table_definition using_rtree_i32(Cs... definition) { internal::validate_rtree_definition(); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(definition)...)}); + return {std::make_tuple(std::forward(definition)...)}; } } #endif diff --git a/examples/rtree.cpp b/examples/rtree.cpp index 5a60a307..b0eb60a2 100644 --- a/examples/rtree.cpp +++ b/examples/rtree.cpp @@ -6,8 +6,9 @@ #include +// note: clang currently has problems to use constexpr variables in lambdas #if defined(SQLITE_ENABLE_RTREE) && SQLITE_VERSION_NUMBER >= 3024000 && defined(SQLITE_ORM_CPP20_RANGES_SUPPORTED) && \ - defined(SQLITE_ORM_WITH_CPP20_ALIASES) + defined(SQLITE_ORM_WITH_CPP20_ALIASES) && !defined(__clang__) #define ENABLE_THIS_EXAMPLE #endif diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d510c88e..4e4e8f90 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1,11 +1,21 @@ #pragma once -// Clang has the annoying habit of warning about future C++ features that it claims to support through a feature macro. #ifdef __clang__ #pragma clang diagnostic push +// Clang has the annoying habit of warning about future C++ features that it claims to support through a feature macro. #pragma clang diagnostic ignored "-Wc++20-extensions" #pragma clang diagnostic ignored "-Wc++23-extensions" #pragma clang diagnostic ignored "-Wc++26-extensions" + +// clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. +// This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, +// see https://en.cppreference.com/w/cpp/language/aggregate_initialization: +// "The braces around the nested initializer lists may be elided (omitted), +// in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, +// and the subsequent initializer clauses are used to initialize the following members of the object." +// In this sense clang should only warn about missing field initializers. +// Because we know what we are doing, we suppress the diagnostic message +#pragma clang diagnostic ignored "-Wmissing-braces" #endif #if defined(_MSC_VER) @@ -161,23 +171,13 @@ using std::nullptr_t; #if defined(_MSC_VER) && !defined(__clang__) #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) SQLITE_ORM_DO_PRAGMA(warning(suppress : warncode)) #else -#define SQLITE_ORM_MSVC_SUPPRESS(warcode, ...) __VA_ARGS__ +#define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ #endif #if defined(_MSC_VER) && defined(__clang__) -#define SQLITE_ORM_CLANG_ON_WIN +#define SQLITE_ORM_CLANG_MSVC #endif -// clang has the bad habit of diagnosing missing brace-init-lists when constructing aggregates with base classes. -// This is a false positive, since the C++ standard is quite clear that braces for nested or base objects may be omitted, -// see https://en.cppreference.com/w/cpp/language/aggregate_initialization: -// "The braces around the nested initializer lists may be elided (omitted), -// in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, -// and the subsequent initializer clauses are used to initialize the following members of the object." -// In this sense clang should only warn about missing field initializers. -// Because we know what we are doing, we suppress the diagnostic message -#define SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(...) SQLITE_ORM_CLANG_SUPPRESS("-Wmissing-braces", __VA_ARGS__) - // msvc has the bad habit of diagnosing overalignment of types with an explicit alignment specifier. #define SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(...) SQLITE_ORM_MSVC_SUPPRESS(4324, __VA_ARGS__) @@ -1712,7 +1712,7 @@ namespace sqlite_orm { return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED +#if defined(SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED) && __cpp_lib_forward_like >= 202207L /* * Like `std::make_from_tuple()`, but using a projection on the tuple elements. */ @@ -1739,7 +1739,7 @@ namespace sqlite_orm { return R{polyfill::invoke(project, std::get(std::forward(tpl)))...}; } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED +#if defined(SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED) && __cpp_lib_forward_like >= 202207L /* * Similar to `create_from_tuple()`, but the result type is specified as a class template. */ @@ -2413,7 +2413,8 @@ namespace sqlite_orm::internal { * Make a table-valued function call. */ template - constexpr table_valued_expression operator()(Args... arguments) const { + constexpr SQLITE_ORM_STATIC_CALLOP table_valued_expression + operator()(Args... arguments) SQLITE_ORM_OR_CONST_CALLOP { return {{ {std::move(arguments)}... }}; } #else @@ -2421,7 +2422,8 @@ namespace sqlite_orm::internal { * Make a table-valued function call. */ template - constexpr table_valued_expression operator()(Args... arguments) const { + constexpr SQLITE_ORM_STATIC_CALLOP table_valued_expression + operator()(Args... arguments) SQLITE_ORM_OR_CONST_CALLOP { return {{ {std::move(arguments)}... }}; } #endif @@ -9120,8 +9122,7 @@ namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}); + return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}; } #endif } @@ -9138,8 +9139,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}); + return {std::move(name), memberPointer, {}, std::tuple{std::move(constraints)...}}; } /** @@ -9157,8 +9157,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}); + return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}; } /** @@ -9176,8 +9175,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { // attention: do not use `std::make_tuple()` for constructing the tuple member `[[no_unique_address]] column_constraints::constraints`, // as this will lead to UB with Clang on MinGW! - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}); + return {std::move(name), getter, setter, std::tuple{std::move(constraints)...}}; } } @@ -10880,7 +10878,7 @@ namespace sqlite_orm { template = true> void operator()(const T& t) { - int rc = statement_binder{}.bind(this->stmt, ++this->nthSqlParameter, t); + const int rc = statement_binder{}.bind(this->stmt, ++this->nthSqlParameter, t); if (SQLITE_OK != rc) SQLITE_ORM_CPP_UNLIKELY /*possible but unexpected*/ { throw_translated_sqlite_error(rc); } @@ -10912,10 +10910,11 @@ namespace sqlite_orm { explicit tuple_value_binder(sqlite3_stmt* stmt) : stmt{stmt} {} #ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED - void operator()(const auto& tpl, auto project) const { + template + void operator()(const Tpl& tpl, Projection project) const { int nthSqlParameter = 0; auto& [... elements] = tpl; - (this->bind(std::invoke(project, elements), ++nthSqlParameter), ...); + (this->bind(polyfill::invoke(project, elements), ++nthSqlParameter), ...); } #else template @@ -10936,7 +10935,7 @@ namespace sqlite_orm { template void bind(const T& t, int nthSqlParameter) const { - int rc = statement_binder{}.bind(this->stmt, nthSqlParameter, t); + const int rc = statement_binder{}.bind(this->stmt, nthSqlParameter, t); if (SQLITE_OK != rc) SQLITE_ORM_CPP_UNLIKELY /*possible but unexpected*/ { throw_translated_sqlite_error(rc); } @@ -12986,8 +12985,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}; } template @@ -12997,8 +12995,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), false, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}; } template @@ -13008,8 +13005,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { using cols_tuple = std::tuple; static_assert(internal::count_tuple::value <= 1, "amount of where arguments can be 0 or 1"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}); + return {std::move(name), true, std::make_tuple(internal::make_indexed_column(std::move(cols))...)}; } } @@ -13123,8 +13119,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { static_assert(polyfill::conjunction_v...>, "Incorrect table elements or constraints"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(definition)...)}); + return {std::move(name), std::make_tuple(std::forward(definition)...)}; } /** @@ -13137,8 +13132,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { static_assert(polyfill::conjunction_v...>, "Incorrect table elements or constraints"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(definition)...)}); + return {std::move(name), std::make_tuple(std::forward(definition)...)}; } #ifdef SQLITE_ORM_WITH_CPP20_ALIASES @@ -14011,7 +14005,7 @@ namespace sqlite_orm { #include // std::integral_constant #endif -#ifdef SQLITE_ORM_CLANG_ON_WIN +#ifdef SQLITE_ORM_CLANG_MSVC namespace sqlite_orm::internal { struct statement_deleter { SQLITE_ORM_STATIC_CALLOP void operator()(sqlite3_stmt* stmt) SQLITE_ORM_OR_CONST_CALLOP noexcept { @@ -14023,7 +14017,7 @@ namespace sqlite_orm::internal { SQLITE_ORM_EXPORT namespace sqlite_orm { -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC /** * Guard class which finalizes `sqlite3_stmt` in dtor */ @@ -14207,7 +14201,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch (int rc = sqlite3_step(stmt)) { + switch (/*int rc =*/sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -14223,7 +14217,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch (int rc = sqlite3_step(stmt)) { + switch (/*int rc =*/sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -15327,7 +15321,7 @@ namespace sqlite_orm { #if SQLITE_VERSION_NUMBER >= 3014000 std::string expanded_sql() const { // note: must check return value due to SQLITE_OMIT_TRACE -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC using char_ptr = std::unique_ptr>; #else struct sqlite3_memory_deleter { @@ -17479,7 +17473,7 @@ namespace sqlite_orm { return stream_identifier(ss, std::get(tpl)...); } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED +#if defined(SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED) && defined(SQLITE_ORM_CONCEPTS_SUPPORTED) template requires polyfill::is_detected_v> void stream_identifier(std::ostream& ss, const Tpl& tpl) { @@ -20956,8 +20950,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { template internal::trigger_t make_trigger(std::string name, const internal::partial_trigger_t& part) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::move(part.base), std::move(part.statements)}); + return {std::move(name), std::move(part.base), std::move(part.statements)}; } inline internal::trigger_timing_t before() { @@ -21100,7 +21093,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { template internal::virtual_table make_virtual_table(std::string name, internal::virtual_table_description description) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(description)}); + return {std::move(name), std::move(description)}; } /** @@ -21111,7 +21104,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { template internal::virtual_table make_virtual_table(std::string name, internal::virtual_table_definition definition) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(name), std::move(definition)}); + return {std::move(name), std::move(definition)}; } /** @@ -23855,8 +23848,7 @@ namespace sqlite_orm { template cte_table make_cte_table(std::string name, Cs... args) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES( - return {std::move(name), std::make_tuple(std::forward(args)...)}); + return {std::move(name), std::make_tuple(std::forward(args)...)}; } // aliased column expressions, explicit or implicitly numbered @@ -25798,7 +25790,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch (int rc = sqlite3_step(stmt)) { + switch (/*int rc =*/sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { @@ -26820,7 +26812,7 @@ namespace sqlite_orm::internal { template inline virtual_table_definition make_dbstat_definition(Cs... columns) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {{std::make_tuple(std::move(columns)...)}}); + return {{std::make_tuple(std::move(columns)...)}}; } } @@ -26958,7 +26950,7 @@ namespace sqlite_orm::internal { template inline virtual_table_definition make_generate_series_definition(Cs... columns) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {{std::make_tuple(std::move(columns)...)}}); + return {{std::make_tuple(std::move(columns)...)}}; } } @@ -27059,7 +27051,7 @@ namespace sqlite_orm::internal { template inline virtual_table_definition make_fts5_definition(Cs... definition) { - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {{std::make_tuple(std::move(definition)...)}}); + return {{std::make_tuple(std::move(definition)...)}}; } } @@ -27142,7 +27134,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { static_assert((internal::is_fts5_table_element_or_constraint_v && ...), "Incorrect table elements or constraints"); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(definition)...)}); + return {std::make_tuple(std::forward(definition)...)}; } template @@ -27158,7 +27150,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { std::get(definition.elements).name = tableName; #endif - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::move(tableName), std::move(definition)}); + return {std::move(tableName), std::move(definition)}; } } #endif @@ -27240,7 +27232,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { internal::virtual_table_definition using_rtree(Cs... definition) { internal::validate_rtree_definition(); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(definition)...)}); + return {std::make_tuple(std::forward(definition)...)}; } /** * Factory function for a RTREE_I32 virtual table definition. @@ -27249,7 +27241,7 @@ SQLITE_ORM_EXPORT namespace sqlite_orm { internal::virtual_table_definition using_rtree_i32(Cs... definition) { internal::validate_rtree_definition(); - SQLITE_ORM_CLANG_SUPPRESS_MISSING_BRACES(return {std::make_tuple(std::forward(definition)...)}); + return {std::make_tuple(std::forward(definition)...)}; } } #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bf1d67db..3a6c311e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -72,7 +72,7 @@ if(MSVC) # C4458: declaration of 'symbol' hides class member /wd4458 # C4458: 'symbol': deprecated - # disabled due to unit tests still testing deprecated features + # disabled due to unit tests testing deprecated features /wd4996) if (CMAKE_CXX_FLAGS MATCHES "/D_UNICODE") # explicitly set the entry point of the executable file, @@ -82,8 +82,13 @@ if(MSVC) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") target_compile_options(unit_tests PUBLIC - # disabled due to unit tests still testing deprecated features - -Wno-deprecated-declarations) + -Wno-c++23-extensions + # disabled due to unit tests testing deprecated features + -Wno-deprecated-declarations + # perfectly valid to have missing field initializers in library's test code + -Wno-missing-field-initializers + # suppress warnings about unused variables in test code + -Wno-unused-variable) endif() target_precompile_headers(unit_tests PRIVATE diff --git a/tests/static_tests/functional/tuple_traits.cpp b/tests/static_tests/functional/tuple_traits.cpp index f35cd84d..60af76ae 100644 --- a/tests/static_tests/functional/tuple_traits.cpp +++ b/tests/static_tests/functional/tuple_traits.cpp @@ -13,7 +13,6 @@ using internal::tuple_has_template; using internal::tuple_has_type; TEST_CASE("tuple traits") { - using empty_tuple_type = std::tuple<>; using tuple_type = std::tuple, primary_key_t<>, std::string>; STATIC_REQUIRE(internal::tuple_has::value); diff --git a/tests/static_tests/virtual_tables.cpp b/tests/static_tests/virtual_tables.cpp index 10042e0b..7ae721ec 100644 --- a/tests/static_tests/virtual_tables.cpp +++ b/tests/static_tests/virtual_tables.cpp @@ -48,7 +48,6 @@ TEST_CASE("generic vtab and dbstat layout tests") { true #endif )); - using table_type = decltype(table); using elements_type = decltype(table.elements); #if SQLITE_VERSION_NUMBER >= 3031000 STATIC_REQUIRE(table_values_index_sequence::size() == 2); diff --git a/tests/xdestroy_handling.cpp b/tests/xdestroy_handling.cpp index 68dbe5a9..0af2a32f 100644 --- a/tests/xdestroy_handling.cpp +++ b/tests/xdestroy_handling.cpp @@ -23,7 +23,7 @@ template inline constexpr delete_default_t delete_default_f{}; #endif -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC using free_t = std::integral_constant; inline constexpr free_t free_f{}; #endif @@ -64,7 +64,7 @@ TEST_CASE("obtain_xdestroy_for") { STATIC_REQUIRE(xDestroy1 == nullptr); REQUIRE(xDestroy1 == nullptr); -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC // free(int*) constexpr xdestroy_fn_t xDestroy2 = obtain_xdestroy_for(free, int_nullptr); STATIC_REQUIRE(xDestroy2 == &free); @@ -120,7 +120,7 @@ TEST_CASE("obtain_xdestroy_for") { #endif #if __cpp_constexpr >= 201907L // Trivial default initialization in constexpr functions -#ifndef SQLITE_ORM_CLANG_ON_WIN +#ifndef SQLITE_ORM_CLANG_MSVC // xdestroy_holder{ free }(int*) constexpr xdestroy_fn_t xDestroy8 = obtain_xdestroy_for(xdestroy_holder{free}, int_nullptr); STATIC_REQUIRE(xDestroy8 == &free); From 4a6947e09bcf4c7c176cbe95b976c0528c59384c Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 24 Nov 2025 21:02:55 +0200 Subject: [PATCH 07/15] Ignore Clang's "-Wunused-lambda-capture" as this is common in generic code --- dev/functional/start_macros.h | 3 +++ include/sqlite_orm/sqlite_orm.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/dev/functional/start_macros.h b/dev/functional/start_macros.h index f5d7e625..329281ab 100644 --- a/dev/functional/start_macros.h +++ b/dev/functional/start_macros.h @@ -16,6 +16,9 @@ // In this sense clang should only warn about missing field initializers. // Because we know what we are doing, we suppress the diagnostic message #pragma clang diagnostic ignored "-Wmissing-braces" + +// Unused lambda captures are common in generic code that involves `if contexpr` or `this`-capture. +#pragma clang diagnostic ignored "-Wunused-lambda-capture" #endif #if defined(_MSC_VER) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 4e4e8f90..9a45e898 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -16,6 +16,9 @@ // In this sense clang should only warn about missing field initializers. // Because we know what we are doing, we suppress the diagnostic message #pragma clang diagnostic ignored "-Wmissing-braces" + +// Unused lambda captures are common in generic code that involves `if contexpr` or `this`-capture. +#pragma clang diagnostic ignored "-Wunused-lambda-capture" #endif #if defined(_MSC_VER) From ca185dc01460a236d16544833b3044893973cefd Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 24 Nov 2025 21:22:58 +0200 Subject: [PATCH 08/15] Reordered test expressions for checking Clang MSVC --- dev/functional/cxx_compiler_quirks.h | 2 +- include/sqlite_orm/sqlite_orm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 52466e3a..6800eea5 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -29,7 +29,7 @@ #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ #endif -#if defined(_MSC_VER) && defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) #define SQLITE_ORM_CLANG_MSVC #endif diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 9a45e898..d5c7054c 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -177,7 +177,7 @@ using std::nullptr_t; #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ #endif -#if defined(_MSC_VER) && defined(__clang__) +#if defined(__clang__) && defined(_MSC_VER) #define SQLITE_ORM_CLANG_MSVC #endif From 7577c9cb506d3b2a8b2b02aecc8d2eb11534bfa6 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 25 Nov 2025 14:41:21 +0200 Subject: [PATCH 09/15] appveyor: Try using clang-14 for C++20 build on Ubuntu worker image clang is using libstd++ by default and chokes when including . --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 6c6c2d57..8a6cc725 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -57,8 +57,8 @@ environment: - job_name: clang, C++20 (with examples) appveyor_build_worker_image: Ubuntu - CC: clang - CXX: clang++ + CC: clang-14 + CXX: clang++-14 SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" # clang was stuck with a parallel build of examples cmake_build_parallel: "" From cea657081e0b462493210873c3c08ab0e28d7ef7 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 25 Nov 2025 22:03:40 +0200 Subject: [PATCH 10/15] Marked unused sqlite3 API return codes `[[maybe_unused]]` --- dev/storage.h | 2 +- dev/util.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/storage.h b/dev/storage.h index 613935be..9921d2c0 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -1656,7 +1656,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch (/*int rc =*/sqlite3_step(stmt)) { + switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { diff --git a/dev/util.h b/dev/util.h index 8d408f6e..0e1815c4 100644 --- a/dev/util.h +++ b/dev/util.h @@ -81,7 +81,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch (/*int rc =*/sqlite3_step(stmt)) { + switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -97,7 +97,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch (/*int rc =*/sqlite3_step(stmt)) { + switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index d5c7054c..29532c3f 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -14204,7 +14204,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch (/*int rc =*/sqlite3_step(stmt)) { + switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -14220,7 +14220,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch (/*int rc =*/sqlite3_step(stmt)) { + switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -25793,7 +25793,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch (/*int rc =*/sqlite3_step(stmt)) { + switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { From 7ec9845a91ecbed8bd4415f6ab1943f461304e6d Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 26 Nov 2025 11:48:15 +0200 Subject: [PATCH 11/15] Revert "appveyor: Try using clang-14 for C++20 build on Ubuntu worker image" This reverts commit 7577c9cb506d3b2a8b2b02aecc8d2eb11534bfa6. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8a6cc725..6c6c2d57 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -57,8 +57,8 @@ environment: - job_name: clang, C++20 (with examples) appveyor_build_worker_image: Ubuntu - CC: clang-14 - CXX: clang++-14 + CC: clang + CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" # clang was stuck with a parallel build of examples cmake_build_parallel: "" From 9f10121aba8a7b100a944ef3dbf8adb1cae9e449 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 26 Nov 2025 11:50:07 +0200 Subject: [PATCH 12/15] appveyor: Used Ubuntu1804 explicitly The "Ubuntu" tagged worker image is now an alias for Ubuntu2204. We still want to stay at the older toolchain in order to catch buggy compiler behavior. --- appveyor.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 6c6c2d57..20c5ad86 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,7 +41,7 @@ environment: cmake_build_parallel: "" - job_name: clang, C++17 - appveyor_build_worker_image: Ubuntu + appveyor_build_worker_image: Ubuntu1804 CC: clang CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" @@ -49,14 +49,14 @@ environment: cmake_build_parallel: "" - job_name: gcc, C++17 - appveyor_build_worker_image: Ubuntu + appveyor_build_worker_image: Ubuntu1804 CC: gcc CXX: g++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_17=ON" cmake_build_parallel: "" - job_name: clang, C++20 (with examples) - appveyor_build_worker_image: Ubuntu + appveyor_build_worker_image: Ubuntu1804 CC: clang CXX: clang++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" @@ -65,7 +65,7 @@ environment: cmake_build_examples: "-DBUILD_EXAMPLES=ON" - job_name: gcc, C++20 - appveyor_build_worker_image: Ubuntu + appveyor_build_worker_image: Ubuntu1804 CC: gcc CXX: g++ SQLITE_ORM_CXX_STANDARD: "-DSQLITE_ORM_ENABLE_CXX_20=ON" @@ -131,7 +131,7 @@ for: # Linux matrix: only: - - appveyor_build_worker_image: Ubuntu + - appveyor_build_worker_image: Ubuntu1804 - appveyor_build_worker_image: Ubuntu2204 init: - |- From 0bc52276e1a42b29391aeb34c47f7d86bd198f31 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 26 Nov 2025 16:30:14 +0200 Subject: [PATCH 13/15] `[[maybe_unused]]` in a switch init-stmt only supported since msvc 1920 --- dev/functional/config.h | 6 ++++++ dev/functional/cxx_compiler_quirks.h | 18 ++++++++++------- dev/storage.h | 2 +- dev/util.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 30 ++++++++++++++++++---------- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/dev/functional/config.h b/dev/functional/config.h index 00899a6b..64a62c3b 100644 --- a/dev/functional/config.h +++ b/dev/functional/config.h @@ -15,6 +15,12 @@ #include #endif +#if !defined(SQLITE_ORM_MS_MSVC) || (_MSC_VER >= 1920) +#define SQLITE_ORM_SWITCH_MAYBE_UNUSED [[maybe_unused]] +#else +#define SQLITE_ORM_SWITCH_MAYBE_UNUSED +#endif + #if __cpp_lib_constexpr_functional >= 201907L #define SQLITE_ORM_CONSTEXPR_CPP20 constexpr #else diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 6800eea5..b8615591 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -20,23 +20,27 @@ #endif #if defined(_MSC_VER) && !defined(__clang__) -#define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) +#define SQLITE_ORM_MS_MSVC +#endif + +#if defined(__clang__) && defined(_MSC_VER) +#define SQLITE_ORM_CLANG_MSVC #endif #if defined(_MSC_VER) && !defined(__clang__) +#define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) +#endif + +#if defined(SQLITE_ORM_MS_MSVC) #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) SQLITE_ORM_DO_PRAGMA(warning(suppress : warncode)) #else #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ #endif -#if defined(__clang__) && defined(_MSC_VER) -#define SQLITE_ORM_CLANG_MSVC -#endif - // msvc has the bad habit of diagnosing overalignment of types with an explicit alignment specifier. #define SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(...) SQLITE_ORM_MSVC_SUPPRESS(4324, __VA_ARGS__) -#if defined(_MSC_VER) && (_MSC_VER < 1920) +#if defined(SQLITE_ORM_MS_MSVC) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION // Type replacement may fail if an alias template has a non-type template parameter from a dependent expression in it, // `e.g. template using is_something = std::bool_constant>;` @@ -52,7 +56,7 @@ // In these cases we have to use helper structures to break down the type alias. // Note that the detection of specific compilers is so complicated because some compilers emulate other compilers, // so we simply exclude all compilers that do not support C++20, even though this test is actually inaccurate. -#if (defined(_MSC_VER) && (_MSC_VER < 1920)) || (!defined(_MSC_VER) && (__cplusplus < 202002L)) +#if (defined(SQLITE_ORM_MS_MSVC) && (_MSC_VER < 1920)) || (!defined(SQLITE_ORM_MS_MSVC) && (__cplusplus < 202002L)) #define SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE #endif diff --git a/dev/storage.h b/dev/storage.h index 9921d2c0..ee207b24 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -1656,7 +1656,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { diff --git a/dev/util.h b/dev/util.h index 0e1815c4..190706d6 100644 --- a/dev/util.h +++ b/dev/util.h @@ -81,7 +81,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -97,7 +97,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 29532c3f..63e6ac5a 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -168,23 +168,27 @@ using std::nullptr_t; #endif #if defined(_MSC_VER) && !defined(__clang__) -#define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) +#define SQLITE_ORM_MS_MSVC +#endif + +#if defined(__clang__) && defined(_MSC_VER) +#define SQLITE_ORM_CLANG_MSVC #endif #if defined(_MSC_VER) && !defined(__clang__) +#define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) +#endif + +#if defined(SQLITE_ORM_MS_MSVC) #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) SQLITE_ORM_DO_PRAGMA(warning(suppress : warncode)) #else #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ #endif -#if defined(__clang__) && defined(_MSC_VER) -#define SQLITE_ORM_CLANG_MSVC -#endif - // msvc has the bad habit of diagnosing overalignment of types with an explicit alignment specifier. #define SQLITE_ORM_MSVC_SUPPRESS_OVERALIGNMENT(...) SQLITE_ORM_MSVC_SUPPRESS(4324, __VA_ARGS__) -#if defined(_MSC_VER) && (_MSC_VER < 1920) +#if defined(SQLITE_ORM_MS_MSVC) && (_MSC_VER < 1920) #define SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION // Type replacement may fail if an alias template has a non-type template parameter from a dependent expression in it, // `e.g. template using is_something = std::bool_constant>;` @@ -200,7 +204,7 @@ using std::nullptr_t; // In these cases we have to use helper structures to break down the type alias. // Note that the detection of specific compilers is so complicated because some compilers emulate other compilers, // so we simply exclude all compilers that do not support C++20, even though this test is actually inaccurate. -#if (defined(_MSC_VER) && (_MSC_VER < 1920)) || (!defined(_MSC_VER) && (__cplusplus < 202002L)) +#if (defined(SQLITE_ORM_MS_MSVC) && (_MSC_VER < 1920)) || (!defined(SQLITE_ORM_MS_MSVC) && (__cplusplus < 202002L)) #define SQLITE_ORM_BROKEN_ALIAS_TEMPLATE_DEPENDENT_EXPR_SFINAE #endif @@ -269,6 +273,12 @@ using std::nullptr_t; #include #endif +#if !defined(SQLITE_ORM_MS_MSVC) || (_MSC_VER >= 1920) +#define SQLITE_ORM_SWITCH_MAYBE_UNUSED [[maybe_unused]] +#else +#define SQLITE_ORM_SWITCH_MAYBE_UNUSED +#endif + #if __cpp_lib_constexpr_functional >= 201907L #define SQLITE_ORM_CONSTEXPR_CPP20 constexpr #else @@ -14204,7 +14214,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -14220,7 +14230,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -25793,7 +25803,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch ([[maybe_unused]] int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { From 264850e41fd89d2170608991f7831fa9c9c29b88 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 26 Nov 2025 16:31:18 +0200 Subject: [PATCH 14/15] Simplified 'xdestroy' unit test file --- tests/xdestroy_handling.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/xdestroy_handling.cpp b/tests/xdestroy_handling.cpp index 0af2a32f..5ec4a1f3 100644 --- a/tests/xdestroy_handling.cpp +++ b/tests/xdestroy_handling.cpp @@ -54,8 +54,7 @@ TEST_CASE("obtain_xdestroy_for") { { constexpr int* int_nullptr = nullptr; -#if !defined(SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION) || \ - (__cpp_constexpr >= 201907L) // Trivial default initialization in constexpr functions +#if !defined(SQLITE_ORM_BROKEN_VARIADIC_PACK_EXPANSION) || defined(SQLITE_ORM_TRIVIAL_DEFAULTINIT_SUPPORTED) constexpr const int* const_int_nullptr = nullptr; #endif @@ -76,20 +75,11 @@ TEST_CASE("obtain_xdestroy_for") { REQUIRE(xDestroy3 == &free); #endif -#if __cpp_constexpr >= 201603L // constexpr lambda // [](void* p){} constexpr auto lambda4_1 = [](void*) {}; constexpr xdestroy_fn_t xDestroy4_1 = obtain_xdestroy_for(lambda4_1, int_nullptr); STATIC_REQUIRE(xDestroy4_1 == lambda4_1); REQUIRE(xDestroy4_1 == lambda4_1); -#else -#if !defined(_MSC_VER) || (_MSC_VER >= 1914) // conversion of lambda closure to function pointer using `+` - // [](void* p){} - auto lambda4_1 = [](void*) {}; - xdestroy_fn_t xDestroy4_1 = obtain_xdestroy_for(lambda4_1, int_nullptr); - REQUIRE(xDestroy4_1 == lambda4_1); -#endif -#endif // [](int* p) { delete p; } #if __cplusplus >= 202002L // default-constructible non-capturing lambdas @@ -119,7 +109,7 @@ TEST_CASE("obtain_xdestroy_for") { REQUIRE((xDestroy7 == &xdestroy_proxy, const int>)); #endif -#if __cpp_constexpr >= 201907L // Trivial default initialization in constexpr functions +#ifdef SQLITE_ORM_TRIVIAL_DEFAULTINIT_SUPPORTED #ifndef SQLITE_ORM_CLANG_MSVC // xdestroy_holder{ free }(int*) constexpr xdestroy_fn_t xDestroy8 = obtain_xdestroy_for(xdestroy_holder{free}, int_nullptr); From e4fc853176039218ddc74b3a20b2ed2333853a90 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 26 Nov 2025 18:49:42 +0200 Subject: [PATCH 15/15] Updated previous commit --- dev/functional/cxx_compiler_quirks.h | 4 ++-- include/sqlite_orm/sqlite_orm.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index b8615591..37bdf77f 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -27,11 +27,11 @@ #define SQLITE_ORM_CLANG_MSVC #endif -#if defined(_MSC_VER) && !defined(__clang__) +#ifdef SQLITE_ORM_MS_MSVC #define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) #endif -#if defined(SQLITE_ORM_MS_MSVC) +#ifdef SQLITE_ORM_MS_MSVC #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) SQLITE_ORM_DO_PRAGMA(warning(suppress : warncode)) #else #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__ diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 63e6ac5a..b2551b63 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -175,11 +175,11 @@ using std::nullptr_t; #define SQLITE_ORM_CLANG_MSVC #endif -#if defined(_MSC_VER) && !defined(__clang__) +#ifdef SQLITE_ORM_MS_MSVC #define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) #endif -#if defined(SQLITE_ORM_MS_MSVC) +#ifdef SQLITE_ORM_MS_MSVC #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) SQLITE_ORM_DO_PRAGMA(warning(suppress : warncode)) #else #define SQLITE_ORM_MSVC_SUPPRESS(warncode, ...) __VA_ARGS__