diff --git a/.clang-format b/.clang-format index 558c0d0ad..4d064552e 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 65f060047..dce93991e 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/CMakeLists.txt b/CMakeLists.txt index e091b46f3..9124ea2c9 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/appveyor.yml b/appveyor.yml index 6c6c2d572..20c5ad860 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: - |- diff --git a/dev/alias.h b/dev/alias.h index e43d7d382..007f9c5c0 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 {}; } @@ -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_column_names_collector.h b/dev/cte_column_names_collector.h index b02fbf204..106d547bf 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/dev/cte_moniker.h b/dev/cte_moniker.h index e723b02d7..a53417cf6 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/cte_storage.h b/dev/cte_storage.h index 8f6095278..d0511b0bd 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/function.h b/dev/function.h index a7660179c..542a53483 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/functional/config.h b/dev/functional/config.h index 00899a6bf..64a62c3bd 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_check_prerequisites.h b/dev/functional/cxx_check_prerequisites.h index 20ed286f5..224364d8d 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/functional/cxx_compiler_quirks.h b/dev/functional/cxx_compiler_quirks.h index 14e0b05db..37bdf77ff 100644 --- a/dev/functional/cxx_compiler_quirks.h +++ b/dev/functional/cxx_compiler_quirks.h @@ -15,35 +15,32 @@ 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 #if defined(_MSC_VER) && !defined(__clang__) +#define SQLITE_ORM_MS_MSVC +#endif + +#if defined(__clang__) && defined(_MSC_VER) +#define SQLITE_ORM_CLANG_MSVC +#endif + +#ifdef SQLITE_ORM_MS_MSVC #define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) #endif -#if defined(_MSC_VER) && !defined(__clang__) +#ifdef SQLITE_ORM_MS_MSVC #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 -// 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__) -#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>;` @@ -59,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/functional/start_macros.h b/dev/functional/start_macros.h index 7ec4f6430..329281ab1 100644 --- a/dev/functional/start_macros.h +++ b/dev/functional/start_macros.h @@ -1,11 +1,24 @@ #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" + +// 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/dev/pointer_value.h b/dev/pointer_value.h index 4727f4ae1..d5cfa3d20 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/dev/prepared_statement.h b/dev/prepared_statement.h index d5a6bc987..e2909bfc7 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_MSVC 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/schema/column.h b/dev/schema/column.h index 35e059499..62e0dad68 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 b6bc92710..00f17b587 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 c6b7bb6cc..9d97e3962 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 0ceb4738d..0bf79e814 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 dbf6dbf43..8a7a57f4d 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 080519ca3..52c9459c4 100644 --- a/dev/serializing_util.h +++ b/dev/serializing_util.h @@ -81,7 +81,13 @@ namespace sqlite_orm { return stream_identifier(ss, "", identifier, ""); } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED + 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)...); + } + +#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) { @@ -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/dev/statement_binder.h b/dev/statement_binder.h index 0ea57f03a..51189b7c3 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 1de4575ff..9f9d92576 100644 --- a/dev/statement_finalizer.h +++ b/dev/statement_finalizer.h @@ -6,11 +6,25 @@ #include // std::integral_constant #endif +#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 { + sqlite3_finalize(stmt); + } + }; +} +#endif + SQLITE_ORM_EXPORT namespace sqlite_orm { +#ifndef SQLITE_ORM_CLANG_MSVC /** * 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/dev/statement_serializer.h b/dev/statement_serializer.h index 0409305b2..f93491242 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/dev/storage.h b/dev/storage.h index 4f0c63bc1..ee207b24e 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 (SQLITE_ORM_SWITCH_MAYBE_UNUSED 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 7819d1ffa..728df4905 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 8a715758f..f3d6d0edb 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 1b88f5892..190706d6a 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 (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 (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/dev/vtabs/dbstat.h b/dev/vtabs/dbstat.h index bcc9b0b5d..6e35a2f30 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 1857c939f..190ac96c9 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 b8d4f0407..cfddc3aa9 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 010936608..52f4d5b60 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 5a60a3075..b0eb60a2e 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 5b81e6de5..b2551b63e 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -1,11 +1,24 @@ #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" + +// 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) @@ -51,7 +64,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) || \ @@ -150,35 +163,32 @@ 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 #if defined(_MSC_VER) && !defined(__clang__) +#define SQLITE_ORM_MS_MSVC +#endif + +#if defined(__clang__) && defined(_MSC_VER) +#define SQLITE_ORM_CLANG_MSVC +#endif + +#ifdef SQLITE_ORM_MS_MSVC #define SQLITE_ORM_DO_PRAGMA(...) __pragma(__VA_ARGS__) #endif -#if defined(_MSC_VER) && !defined(__clang__) +#ifdef SQLITE_ORM_MS_MSVC #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 -// 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__) -#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>;` @@ -194,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 @@ -263,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 @@ -1709,7 +1725,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. */ @@ -1736,7 +1752,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. */ @@ -2410,7 +2426,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 @@ -2418,7 +2435,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 @@ -2960,7 +2978,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 {}; } @@ -3050,7 +3068,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{}); } @@ -3060,7 +3078,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{}); } } @@ -3073,7 +3091,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'); @@ -8875,7 +8893,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{}; } @@ -8885,7 +8903,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 @@ -9117,8 +9135,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 } @@ -9135,8 +9152,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)...}}; } /** @@ -9154,8 +9170,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)...}}; } /** @@ -9173,8 +9188,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)...}}; } } @@ -10334,7 +10348,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{}); } } @@ -10877,7 +10891,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); } @@ -10909,10 +10923,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 @@ -10933,7 +10948,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); } @@ -12060,7 +12075,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; } } @@ -12983,8 +12998,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 @@ -12994,8 +13008,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 @@ -13005,8 +13018,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))...)}; } } @@ -13120,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)...)}; } /** @@ -13134,8 +13145,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 @@ -14008,13 +14018,27 @@ namespace sqlite_orm { #include // std::integral_constant #endif +#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 { + sqlite3_finalize(stmt); + } + }; +} +#endif + SQLITE_ORM_EXPORT namespace sqlite_orm { +#ifndef SQLITE_ORM_CLANG_MSVC /** * 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" @@ -14190,7 +14214,7 @@ namespace sqlite_orm { template void perform_step(sqlite3_stmt* stmt, L&& lambda) { - switch (int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -14206,7 +14230,7 @@ namespace sqlite_orm { template void perform_steps(sqlite3_stmt* stmt, L&& lambda) { for (;;) { - switch (int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: { lambda(stmt); } break; @@ -15310,7 +15334,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_MSVC 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 { @@ -17446,7 +17480,13 @@ namespace sqlite_orm { return stream_identifier(ss, "", identifier, ""); } -#ifdef SQLITE_ORM_STRUCTURED_BINDING_PACK_SUPPORTED + 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)...); + } + +#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) { @@ -17455,12 +17495,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) { @@ -20544,7 +20578,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); } @@ -20929,8 +20963,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() { @@ -21073,7 +21106,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)}; } /** @@ -21084,7 +21117,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)}; } /** @@ -21150,7 +21183,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); @@ -23828,8 +23861,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 @@ -25771,7 +25803,7 @@ namespace sqlite_orm { this->executor.will_run_query(sql); } - switch (int rc = sqlite3_step(stmt)) { + switch (SQLITE_ORM_SWITCH_MAYBE_UNUSED int rc = sqlite3_step(stmt)) { case SQLITE_ROW: break; case SQLITE_DONE: { @@ -26793,7 +26825,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)...)}}; } } @@ -26931,7 +26963,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)...)}}; } } @@ -27032,7 +27064,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)...)}}; } } @@ -27115,7 +27147,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 @@ -27131,7 +27163,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 @@ -27213,7 +27245,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. @@ -27222,7 +27254,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 bf1d67dbe..3a6c311e1 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 f35cd84d7..60af76aea 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 10042e0ba..7ae721ecd 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/user_defined_functions.cpp b/tests/user_defined_functions.cpp index c54a0b01f..67d25abb0 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) { diff --git a/tests/xdestroy_handling.cpp b/tests/xdestroy_handling.cpp index 93503abf3..5ec4a1f33 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_MSVC using free_t = std::integral_constant; inline constexpr free_t free_f{}; +#endif TEST_CASE("obtain_xdestroy_for") { @@ -52,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 @@ -62,6 +63,7 @@ TEST_CASE("obtain_xdestroy_for") { STATIC_REQUIRE(xDestroy1 == nullptr); REQUIRE(xDestroy1 == nullptr); +#ifndef SQLITE_ORM_CLANG_MSVC // free(int*) constexpr xdestroy_fn_t xDestroy2 = obtain_xdestroy_for(free, int_nullptr); STATIC_REQUIRE(xDestroy2 == &free); @@ -71,21 +73,13 @@ 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){} 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 @@ -115,7 +109,8 @@ 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); STATIC_REQUIRE(xDestroy8 == &free); @@ -130,6 +125,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