google/fruit

Cannot build registerConstructor with MSVC 2019 /std:c++17

tt4g opened this issue · 7 comments

tt4g commented

I get error "include\fruit\impl/component_functors.defn.h(924,40): error C2066: cast to function type is illegal" when building fruit by CMake.

Reproduction command line(Windows 10, Visual Studio 2019 16.4.5 amd64):

$ mkdir cmake_build
$ cd cmake_build
$ cmake .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON -DCMAKE_CXX_EXTENSIONS=OFF -DBUILD_SHARED_LIBS=OFF -DFRUIT_USES_BOOST=OFF -DFRUIT_TESTS_USE_PRECOMPILED_HEADERS=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE
$ cmake --build . --target

cmake --build . --target log (sorry, error messages are in Japanese. file encoding is UTF-8):
build_log.txt

However, I have confirmed that I can build by changing the configuration to C ++ standard 14.
Another ways, apply the following patch:

diff --git a/examples/scaling_doubles/multiplier.cpp b/examples/scaling_doubles/multiplier.cpp
index be0d349..d030da8 100644
--- a/examples/scaling_doubles/multiplier.cpp
+++ b/examples/scaling_doubles/multiplier.cpp
@@ -24,5 +24,8 @@ public:
 };

 fruit::Component<Multiplier> getMultiplierComponent() {
-  return fruit::createComponent().bind<Multiplier, MultiplierImpl>().registerConstructor<MultiplierImpl()>();
+  return fruit::createComponent().bind<Multiplier, MultiplierImpl>().registerProvider([]()
+  {
+    return MultiplierImpl{};
+  });
 }
tt4g commented

Visual Studio 2017 did not reproduce this problem.

Due to the complexity of the templates used inside the fruit, it was not possible to determine whether this bug was caused by Visual Studio or fruit.

tt4g commented

I modified the source code and found the code that seems to be the cause.
See this line in include/fruit/impl/component_functors.defn.h:

void operator()(FixedSizeVector<ComponentStorageEntry>& entries) {
using NakedC = UnwrapType<Eval<C>>;
auto provider = [](const UnwrapType<Eval<CFunctor>>& fun) {
return UnwrapType<Eval<IFunctor>>([=](typename TypeUnwrapper<Args>::type... args) {
NakedC* c = fun(args...).release();
NakedI* i = static_cast<NakedI*>(c);
return std::unique_ptr<NakedI>(i);
});
};
using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);

I added static_assert(std::is_pointer_v<decltype(provider)>, "std::is_pointer_v<decltype(provider)>");:

diff --git a/include/fruit/impl/component_functors.defn.h b/include/fruit/impl/component_functors.defn.h
index e03b0a8..a9183e2 100644
--- a/include/fruit/impl/component_functors.defn.h
+++ b/include/fruit/impl/component_functors.defn.h
@@ -921,6 +921,9 @@ struct AutoRegisterFactoryHelper {
             return std::unique_ptr<NakedI>(i);
           });
         };
+
+        static_assert(std::is_pointer_v<decltype(provider)>, "std::is_pointer_v<decltype(provider)>");
+
         using RealF2 = ComponentFunctor(PreProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
         using RealF3 = ComponentFunctor(PostProcessRegisterProvider, ProvidedSignature, Type<decltype(provider)>);
         using RealOp = Call(ComposeFunctors(F1, RealF2, RealF3), Comp);

Assertions fail when building Visual Studio 2019 C++14. But with Visual Studio 2019 C++17 the assertion did not fail.

Compilation fails, probably because decltype(provider) is a function pointer.

tt4g commented

I tried altering the provider lambda to a struct provider, but could not compile by MSVC 2019 C++17.

The workaround is to not use registerConstructor().
Exclude the CMake target examples when building with CMake.

Thanks for the report, I'll look into this when I have some time (hopefully next weekend).

tt4g commented

I noticed that this issue does not reproduce in Release build.
Reproduce with Debug build.

I fixed this in 074c1a3.

tt4g commented

Thank you!