diff --git a/include/iris/config.hpp b/include/iris/config.hpp index d258061..2ff9108 100644 --- a/include/iris/config.hpp +++ b/include/iris/config.hpp @@ -7,6 +7,27 @@ #include +#if defined(_MSC_VER) && \ + !defined(__clang__) && \ + !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER) +# define IRIS_COMPILER_STRICTLY_MSVC 1 +#else +# define IRIS_COMPILER_STRICTLY_MSVC 0 +#endif + +#if defined(_MSC_VER) && defined(__clang__) +# define IRIS_COMPILER_CLANG_CL 1 +#else +# define IRIS_COMPILER_CLANG_CL 0 +#endif + +#if defined(_MSC_VER) && defined(__INTELLISENSE__) +# define IRIS_MSVC_INTELLISENSE 1 +#else +# define IRIS_MSVC_INTELLISENSE 0 +#endif + + #if _MSC_VER # include # pragma warning(default: CPPCORECHECK_LIFETIME_WARNINGS) @@ -18,26 +39,53 @@ # error "Too old MSVC version; we don't support this because it leads to ODR violation regarding the existence of [[(msvc::)no_unique_address]]" #endif -#if _MSC_VER && __INTELLISENSE__ // Memory Layout view shows wrong layout without this workaround +#if IRIS_MSVC_INTELLISENSE // Memory Layout view shows wrong layout without this workaround # define IRIS_NO_UNIQUE_ADDRESS [[msvc::no_unique_address, no_unique_address]] -#elif _MSC_VER // normal MSVC +#elif IRIS_COMPILER_STRICTLY_MSVC # define IRIS_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] -#else // other compilers +#elif defined(_MSC_VER) +# if __has_cpp_attribute(msvc::no_unique_address) +# define IRIS_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +# else +# define IRIS_NO_UNIQUE_ADDRESS [[no_unique_address]] +# endif + +#else # define IRIS_NO_UNIQUE_ADDRESS [[no_unique_address]] #endif -#ifndef IRIS_LIFETIMEBOUND -# ifdef __clang__ -# define IRIS_LIFETIMEBOUND [[clang::lifetimebound]] -# elifdef _MSC_VER -# define IRIS_LIFETIMEBOUND [[msvc::lifetimebound]] + +#if IRIS_COMPILER_STRICTLY_MSVC +# define IRIS_EBO __declspec(empty_bases) + +#elif IRIS_COMPILER_CLANG_CL +# if __has_declspec_attribute(empty_bases) +# define IRIS_EBO __declspec(empty_bases) # else -# define IRIS_LIFETIMEBOUND +# define IRIS_EBO # endif + +#else +# define IRIS_EBO #endif + +#if IRIS_MSVC_INTELLISENSE +# define IRIS_LIFETIMEBOUND [[msvc::lifetimebound]] + +#elif __has_cpp_attribute(clang::lifetimebound) +# define IRIS_LIFETIMEBOUND [[clang::lifetimebound]] + +#elif __has_cpp_attribute(msvc::lifetimebound) +# define IRIS_LIFETIMEBOUND [[msvc::lifetimebound]] + +#else +# define IRIS_LIFETIMEBOUND +#endif + + #if __cpp_consteval >= 202211L # define IRIS_CONSTEXPR_UP constexpr #else diff --git a/test/core.cpp b/test/core.cpp index d66fe74..30dd18d 100644 --- a/test/core.cpp +++ b/test/core.cpp @@ -20,6 +20,49 @@ namespace unit_test { +TEST_CASE("EBO") +{ + // https://learn.microsoft.com/en-us/cpp/cpp/empty-bases + + struct Empty1 {}; + STATIC_CHECK(sizeof(Empty1) == 1); + + struct Struct1 { char c; }; + STATIC_CHECK(sizeof(Struct1) == 1); + + struct Derived1 : Empty1 { char c; }; + STATIC_CHECK(sizeof(Derived1) == 1); + + struct Empty2 : Empty1 {}; + struct Derived2 : Empty2 { char c; }; + STATIC_CHECK(sizeof(Derived2) == 1); + + struct Empty3 {}; + struct Derived3 : Empty2, Empty3 { char c; }; + struct Derived4 : Empty2, Empty3 { std::int32_t i; }; + struct Struct2 : Struct1, Empty1 {}; + STATIC_CHECK(sizeof(Struct2) == 1); + +#if !IRIS_COMPILER_STRICTLY_MSVC + STATIC_CHECK(sizeof(Derived3) == 1); + STATIC_CHECK(sizeof(Derived4) == 4); +#endif + + struct IRIS_EBO Derived3_fixed : Empty2, Empty3 { char c; }; + STATIC_CHECK(sizeof(Derived3_fixed) == 1); + + struct IRIS_EBO Derived4_fixed : Empty2, Empty3 { std::int32_t i; }; + STATIC_CHECK(sizeof(Derived4_fixed) == 4); + + struct IRIS_EBO Derived5 : Derived4 {}; +#if !IRIS_COMPILER_STRICTLY_MSVC + STATIC_CHECK(sizeof(Derived5) == 4); +#endif + + struct Derived5_fixed : Derived4_fixed {}; + STATIC_CHECK(sizeof(Derived5_fixed) == 4); +} + TEST_CASE("pack_indexing") { STATIC_REQUIRE(std::is_same_v, int>);