From 3ccb5e1cd707fbb8a683a1ddbc81ec97e499010c Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sat, 11 Jul 2020 15:25:22 -0700 Subject: Report a more user-friendly error when passing a signature with Assisted params to registerConstructor or when attempting to use implicit constructor injection for a constructor that has assisted params. --- include/fruit/impl/component_functors.defn.h | 6 ++-- include/fruit/impl/injection_errors.h | 15 ++++++++++ tests/test_register_constructor.py | 41 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/include/fruit/impl/component_functors.defn.h b/include/fruit/impl/component_functors.defn.h index b12f723..83ef385 100644 --- a/include/fruit/impl/component_functors.defn.h +++ b/include/fruit/impl/component_functors.defn.h @@ -570,8 +570,8 @@ struct PreProcessRegisterConstructor { using CDeps = NormalizeTypeVector(AnnotatedArgs); using CNonConstDeps = NormalizedNonConstTypesIn(AnnotatedArgs); using R = AddProvidedType(Comp, AnnotatedC, Bool, CDeps, CNonConstDeps); - using type = If( - Not(IsValidSignature(AnnotatedSignature)), ConstructError(NotASignatureErrorTag, AnnotatedSignature), + using type = If(Not(IsValidSignature(AnnotatedSignature)), ConstructError(NotASignatureErrorTag, AnnotatedSignature), + If(Not(IsSame(RemoveAssisted(Args), Args)), ConstructError(AssistedParamInRegisterConstructorSignatureErrorTag, AnnotatedSignature), PropagateError(CheckInjectableType(RemoveAnnotations(C)), PropagateError(CheckInjectableTypeVector(RemoveAnnotationsFromVector(Args)), If(IsAbstract(RemoveAnnotations(SignatureType(AnnotatedSignature))), @@ -579,7 +579,7 @@ struct PreProcessRegisterConstructor { RemoveAnnotations(SignatureType(AnnotatedSignature))), If(Not(IsConstructibleWithVector(C, Args)), ConstructError(NoConstructorMatchingInjectSignatureErrorTag, C, Signature), - PropagateError(R, ComponentFunctorIdentity(R))))))); + PropagateError(R, ComponentFunctorIdentity(R)))))))); }; }; diff --git a/include/fruit/impl/injection_errors.h b/include/fruit/impl/injection_errors.h index a0e9def..68247d2 100644 --- a/include/fruit/impl/injection_errors.h +++ b/include/fruit/impl/injection_errors.h @@ -124,6 +124,16 @@ struct NotASignatureError { "the form MyClass(int, float)."); }; +template +struct AssistedParamInRegisterConstructorSignatureError { + static_assert(AlwaysFalse::value, + "CandidateSignature was used as signature for a registerConstructor() (explicit or implicit via the " + "INJECT macro / Inject typedef) but it contains an assisted parameter. When using assisted parameters" + "You need to inject a factory like std::function(int, float)> instead of " + "injecting MyClass directly. If you used an explicit registerConstructor(), you also need to switch " + "that to registerFactory()."); +}; + template struct NotALambdaError { static_assert(AlwaysFalse::value, @@ -494,6 +504,11 @@ struct NotASignatureErrorTag { using apply = NotASignatureError; }; +struct AssistedParamInRegisterConstructorSignatureErrorTag { + template + using apply = AssistedParamInRegisterConstructorSignatureError; +}; + struct NotALambdaErrorTag { template using apply = NotALambdaError; diff --git a/tests/test_register_constructor.py b/tests/test_register_constructor.py index 3e5137e..b78191f 100755 --- a/tests/test_register_constructor.py +++ b/tests/test_register_constructor.py @@ -587,5 +587,46 @@ class TestRegisterConstructor(parameterized.TestCase): source, locals()) + def test_register_constructor_error_assisted_param(self): + source = ''' + struct X { + INJECT(X(ASSISTED(double) factor)) { + (void) factor; + } + }; + + fruit::Component getComponent() { + return fruit::createComponent() + .registerConstructor)>(); + } + ''' + expect_compile_error( + 'AssistedParamInRegisterConstructorSignatureError\\)>', + 'CandidateSignature was used as signature for a registerConstructor.* but it contains an assisted parameter.', + COMMON_DEFINITIONS, + source, + locals()) + + def test_implicit_register_constructor_error_assisted_param(self): + source = ''' + struct X { + INJECT(X(ASSISTED(double) factor)) { + (void) factor; + } + }; + + fruit::Component getComponent() { + return fruit::createComponent(); + } + ''' + expect_compile_error( + 'AssistedParamInRegisterConstructorSignatureError\\)>', + 'CandidateSignature was used as signature for a registerConstructor.* but it contains an assisted parameter.', + COMMON_DEFINITIONS, + source, + locals()) + + + if __name__ == '__main__': absltest.main() -- cgit v1.2.3 From 987716be45d64c81fc5117a72335c437b7e36b5a Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sat, 11 Jul 2020 15:31:10 -0700 Subject: Pass another flag to force installation of required brew packages in OS X CI tests. --- extras/scripts/travis_ci_install_osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/scripts/travis_ci_install_osx.sh b/extras/scripts/travis_ci_install_osx.sh index 2cbd357..d3cc7c8 100755 --- a/extras/scripts/travis_ci_install_osx.sh +++ b/extras/scripts/travis_ci_install_osx.sh @@ -12,7 +12,7 @@ done install_brew_package() { time (brew install "$@" || brew outdated "$1" || brew upgrade "$@" || true) # Some formulas are not linked into /usr/local by default, make sure they are. - time (brew link --force "$@" || true) + time (brew link --force --overwrite "$@" || true) } # For md5sum, timeout -- cgit v1.2.3 From c60370e7a9ff2abcba86e5289a9904213983dfc6 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 12 Jul 2020 00:32:31 -0700 Subject: Make the test_headers_copy library a static library. This fixes CI tests for Visual Studio, where otherwise it would generate a .dll instead of the expected .lib file. --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 479b8aa..095d3db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -81,7 +81,7 @@ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(MSVC)$") set(FRUIT_TESTONLY_CXXFLAGS "${FRUIT_TESTONLY_CXXFLAGS} /wd4702 /wd4503") endif() -add_library(test_headers_copy SHARED test_common.cpp) +add_library(test_headers_copy STATIC test_common.cpp) target_link_libraries(test_headers_copy fruit) # Escape the backslash which is a Windows path separator. -- cgit v1.2.3 From aeb903162f2c6bbcc378e8024142995cae79e6f8 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 12 Jul 2020 09:59:08 -0700 Subject: Configure the Github source code language analyzer to skip py files, otherwise Fruit gets listed as a Python project since there's more Python (in tests) than C++ (in the implementation). --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..912b302 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.py linguist-detectable=false -- cgit v1.2.3 From 29c9fd265cfa72ee72fb64257fe4b72198d87264 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 12 Jul 2020 10:02:58 -0700 Subject: Bump the Fruit version to 3.6.0. --- CMakeLists.txt | 2 +- conanfile.py | 2 +- extras/packaging/deploy_to_bintray.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5b6a64..7efcf7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.2) -project(Fruit VERSION 3.5.0 LANGUAGES CXX) +project(Fruit VERSION 3.6.0 LANGUAGES CXX) set(FRUIT_IS_BEING_BUILT_BY_CONAN FALSE CACHE BOOL "This is set in Conan builds.") if("${FRUIT_IS_BEING_BUILT_BY_CONAN}") diff --git a/conanfile.py b/conanfile.py index 9c87a68..a96d39c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -5,7 +5,7 @@ import os class FruitConan(ConanFile): name = "fruit" - version = "3.5.0" + version = "3.6.0" license = "Apache" url = "https://github.com/google/fruit" homepage = "https://github.com/google/fruit" diff --git a/extras/packaging/deploy_to_bintray.sh b/extras/packaging/deploy_to_bintray.sh index 0365a6d..78d5c51 100755 --- a/extras/packaging/deploy_to_bintray.sh +++ b/extras/packaging/deploy_to_bintray.sh @@ -1,6 +1,6 @@ #!/bin/bash -FRUIT_VERSION=3.5.0 +FRUIT_VERSION=3.6.0 # To authenticate: # conan user -p -r fruit-bintray polettimarco -- cgit v1.2.3 From 94cefefb42f3685c1d64664e6aa9cbaf834b25ee Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 9 Aug 2020 11:02:44 -0700 Subject: Automatically detect compiler features when running under Bazel. Before this commit, bazel builds used a hardcoded configuration, but that doesn't work e.g. on Windows where MSVC needs a different config. --- BUILD | 7 +- configuration/bazel/BUILD | 8 ++ configuration/bazel/always_inline_attribute.cpp | 7 ++ configuration/bazel/attribute_deprecated.cpp | 5 ++ configuration/bazel/build_defs.bzl | 85 ++++++++++++++++++++++ configuration/bazel/builtin_unreachable.cpp | 13 ++++ .../clang_arbitrary_overload_resolution_bug.cpp | 11 +++ configuration/bazel/constexpr_typeid.cpp | 6 ++ configuration/bazel/cxa_demangle.cpp | 6 ++ configuration/bazel/declspec_deprecated.cpp | 5 ++ configuration/bazel/force_inline.cpp | 7 ++ configuration/bazel/fruit/impl/fruit-config-base.h | 70 ------------------ configuration/bazel/gcc_attribute_deprecated.cpp | 5 ++ configuration/bazel/has_trivial_copy.cpp | 5 ++ configuration/bazel/is_trivially_copyable.cpp | 5 ++ configuration/bazel/max_align_t.cpp | 5 ++ configuration/bazel/msvc_assume.cpp | 13 ++++ .../bazel/std_is_trivially_copy_constructible.cpp | 6 ++ configuration/bazel/std_is_trivially_copyable.cpp | 6 ++ configuration/bazel/std_max_align_t.cpp | 5 ++ configuration/bazel/typeid.cpp | 5 ++ 21 files changed, 212 insertions(+), 73 deletions(-) create mode 100644 configuration/bazel/BUILD create mode 100644 configuration/bazel/always_inline_attribute.cpp create mode 100644 configuration/bazel/attribute_deprecated.cpp create mode 100644 configuration/bazel/build_defs.bzl create mode 100644 configuration/bazel/builtin_unreachable.cpp create mode 100644 configuration/bazel/clang_arbitrary_overload_resolution_bug.cpp create mode 100644 configuration/bazel/constexpr_typeid.cpp create mode 100644 configuration/bazel/cxa_demangle.cpp create mode 100644 configuration/bazel/declspec_deprecated.cpp create mode 100644 configuration/bazel/force_inline.cpp delete mode 100644 configuration/bazel/fruit/impl/fruit-config-base.h create mode 100644 configuration/bazel/gcc_attribute_deprecated.cpp create mode 100644 configuration/bazel/has_trivial_copy.cpp create mode 100644 configuration/bazel/is_trivially_copyable.cpp create mode 100644 configuration/bazel/max_align_t.cpp create mode 100644 configuration/bazel/msvc_assume.cpp create mode 100644 configuration/bazel/std_is_trivially_copy_constructible.cpp create mode 100644 configuration/bazel/std_is_trivially_copyable.cpp create mode 100644 configuration/bazel/std_max_align_t.cpp create mode 100644 configuration/bazel/typeid.cpp diff --git a/BUILD b/BUILD index 7d781ee..4c2aef5 100644 --- a/BUILD +++ b/BUILD @@ -6,8 +6,9 @@ filegroup( name = "fruit_headers", srcs = glob([ "include/**/*.h", - "configuration/bazel/**/*.h", - ]), + ]) + [ + "//third_party/fruit/configuration/bazel:fruit_config", + ], ) cc_library( @@ -15,7 +16,7 @@ cc_library( srcs = glob([ "src/*.cpp", "include/fruit/impl/**/*.h", - "configuration/bazel/**/*.h"]), + ]) + ["//third_party/fruit/configuration/bazel:fruit_config"], hdrs = glob(["include/fruit/*.h"]), includes = ["include", "configuration/bazel"], deps = [ diff --git a/configuration/bazel/BUILD b/configuration/bazel/BUILD new file mode 100644 index 0000000..112b732 --- /dev/null +++ b/configuration/bazel/BUILD @@ -0,0 +1,8 @@ +load("//third_party/fruit/configuration/bazel:build_defs.bzl", "generate_fruit_config") + +package(default_visibility = ["//third_party/fruit:__subpackages__"]) + +generate_fruit_config( + name = "fruit_config", + check_sources = glob(["*.cpp"]) +) diff --git a/configuration/bazel/always_inline_attribute.cpp b/configuration/bazel/always_inline_attribute.cpp new file mode 100644 index 0000000..e6215af --- /dev/null +++ b/configuration/bazel/always_inline_attribute.cpp @@ -0,0 +1,7 @@ +__attribute__((always_inline)) +void f() { +} + +int main() { + return 0; +} diff --git a/configuration/bazel/attribute_deprecated.cpp b/configuration/bazel/attribute_deprecated.cpp new file mode 100644 index 0000000..245519d --- /dev/null +++ b/configuration/bazel/attribute_deprecated.cpp @@ -0,0 +1,5 @@ +[[deprecated]] void f(); + +int main() { + return 0; +} diff --git a/configuration/bazel/build_defs.bzl b/configuration/bazel/build_defs.bzl new file mode 100644 index 0000000..8d683c4 --- /dev/null +++ b/configuration/bazel/build_defs.bzl @@ -0,0 +1,85 @@ +load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME") +load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain") + +def _generate_fruit_config_impl(ctx): + cc_toolchain = find_cpp_toolchain(ctx) + + feature_configuration = cc_common.configure_features( + ctx = ctx, + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + c_compiler_path = cc_common.get_tool_for_action( + feature_configuration = feature_configuration, + action_name = C_COMPILE_ACTION_NAME, + ) + + check_output_files = [] + for check_source in ctx.files.check_sources: + output_file = ctx.actions.declare_file(check_source.path + ".o") + + c_compile_variables = cc_common.create_compile_variables( + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts, + source_file = check_source.path, + output_file = output_file.path, + ) + command_line = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = C_COMPILE_ACTION_NAME, + variables = c_compile_variables, + ) + env = cc_common.get_environment_variables( + feature_configuration = feature_configuration, + action_name = C_COMPILE_ACTION_NAME, + variables = c_compile_variables, + ) + + check_name = check_source.path.split('/')[-1].split('\\')[-1] + check_define = 'FRUIT_HAS_%s' % check_name.upper() + check_output_file = ctx.actions.declare_file(check_source.path + ".h") + + ctx.actions.run_shell( + command = '"$@" &>/dev/null && echo "#define %s 1" >"%s" || echo "#define %s 0" >"%s"; touch "%s"' % ( + check_define, check_output_file.path, check_define, check_output_file.path, output_file.path + ), + arguments = [c_compiler_path] + command_line, + env = env, + inputs = depset( + [check_source], + transitive = [cc_toolchain.all_files], + ), + outputs = [output_file, check_output_file], + ) + check_output_files.append(check_output_file) + + merged_output_file = ctx.actions.declare_file(ctx.label.name + ".h") + ctx.actions.run_shell( + command = '\n'.join([ + '(', + 'echo "#ifndef FRUIT_CONFIG_BASE_H"', + 'echo "#define FRUIT_CONFIG_BASE_H"', + 'echo "#define FRUIT_USES_BOOST 1"', + 'cat %s' % ' '.join([check_output_file.path for check_output_file in check_output_files]), + 'echo "#endif"', + ')>%s' % merged_output_file.path + ]), + inputs = check_output_files, + outputs = [merged_output_file], + ) + + return [ + DefaultInfo(files = depset([merged_output_file])), + ] + +generate_fruit_config = rule( + implementation = _generate_fruit_config_impl, + attrs = { + "check_sources": attr.label_list(allow_files = True), + "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + }, + toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], + fragments = ["cpp"], +) \ No newline at end of file diff --git a/configuration/bazel/builtin_unreachable.cpp b/configuration/bazel/builtin_unreachable.cpp new file mode 100644 index 0000000..11d20cf --- /dev/null +++ b/configuration/bazel/builtin_unreachable.cpp @@ -0,0 +1,13 @@ +int f() { + static int x = 1; + if (x == 1) { + return 0; + } else { + __builtin_unreachable(); + // Note: the lack of return here is intentional + } +} + +int main() { + return f(); +} diff --git a/configuration/bazel/clang_arbitrary_overload_resolution_bug.cpp b/configuration/bazel/clang_arbitrary_overload_resolution_bug.cpp new file mode 100644 index 0000000..67b4317 --- /dev/null +++ b/configuration/bazel/clang_arbitrary_overload_resolution_bug.cpp @@ -0,0 +1,11 @@ +template +struct Pair {}; + +struct Map : public Pair, Pair {}; + +template +Value f(Pair*) { return Value(); } + +int main() { + f((Map*)0); +} diff --git a/configuration/bazel/constexpr_typeid.cpp b/configuration/bazel/constexpr_typeid.cpp new file mode 100644 index 0000000..a793377 --- /dev/null +++ b/configuration/bazel/constexpr_typeid.cpp @@ -0,0 +1,6 @@ +#include +int main() { + constexpr static const std::type_info& x = typeid(int); + (void) x; + return 0; +} diff --git a/configuration/bazel/cxa_demangle.cpp b/configuration/bazel/cxa_demangle.cpp new file mode 100644 index 0000000..3e4f57f --- /dev/null +++ b/configuration/bazel/cxa_demangle.cpp @@ -0,0 +1,6 @@ +#include +int main() { + auto* p = abi::__cxa_demangle; + (void) p; + return 0; +} diff --git a/configuration/bazel/declspec_deprecated.cpp b/configuration/bazel/declspec_deprecated.cpp new file mode 100644 index 0000000..79a9f43 --- /dev/null +++ b/configuration/bazel/declspec_deprecated.cpp @@ -0,0 +1,5 @@ +__declspec(deprecated) void f(); + +int main() { + return 0; +} diff --git a/configuration/bazel/force_inline.cpp b/configuration/bazel/force_inline.cpp new file mode 100644 index 0000000..fab42d2 --- /dev/null +++ b/configuration/bazel/force_inline.cpp @@ -0,0 +1,7 @@ +__forceinline +void f() { +} + +int main() { + return 0; +} diff --git a/configuration/bazel/fruit/impl/fruit-config-base.h b/configuration/bazel/fruit/impl/fruit-config-base.h deleted file mode 100644 index 8e7af1d..0000000 --- a/configuration/bazel/fruit/impl/fruit-config-base.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FRUIT_CONFIG_BASE_H -#define FRUIT_CONFIG_BASE_H - -// Needed for all Clang versions (as of January 2016), not needed for GCC. -// This can also be defined for GCC, but it slightly slows down compile time of code using Fruit. -#define FRUIT_HAS_CLANG_ARBITRARY_OVERLOAD_RESOLUTION_BUG 1 - -// Whether the compiler defines std::max_align_t. -#define FRUIT_HAS_STD_MAX_ALIGN_T 1 - -// Whether the compiler defines ::max_align_t. -// Ignored if FRUIT_HAS_STD_MAX_ALIGN_T is set. -#define FRUIT_HAS_MAX_ALIGN_T 1 - -// Whether the compiler defines std::is_trivially_copyable. -#define FRUIT_HAS_STD_IS_TRIVIALLY_COPYABLE 1 - -// Whether the compiler defines __has_trivial_copy. -// Ignored if FRUIT_HAS_STD_IS_TRIVIALLY_COPYABLE is set. -#define FRUIT_HAS_HAS_TRIVIAL_COPY 1 - -// Whether the compiler defines __is_trivially_copyable. -// Ignored if FRUIT_HAS_STD_IS_TRIVIALLY_COPYABLE is set. -#define FRUIT_HAS_IS_TRIVIALLY_COPYABLE 1 - -// Whether the compiler defines std::is_trivially_copy_constructible. -#define FRUIT_HAS_STD_IS_TRIVIALLY_COPY_CONSTRUCTIBLE 1 - -// Whether typeid() is available. Typically, it is unless RTTI is disabled. -#define FRUIT_HAS_TYPEID 1 - -// Whether typeid() is constexpr. Typically, it is except in MSVC. -#define FRUIT_HAS_CONSTEXPR_TYPEID 1 - -// Whether abi::__cxa_demangle() is available after including cxxabi.h. -#define FRUIT_HAS_CXA_DEMANGLE 1 - -#define FRUIT_USES_BOOST 1 - -#define FRUIT_HAS_ALWAYS_INLINE_ATTRIBUTE 1 - -#define FRUIT_HAS_FORCEINLINE 0 - -#define FRUIT_HAS_ATTRIBUTE_DEPRECATED 0 - -#define FRUIT_HAS_GCC_ATTRIBUTE_DEPRECATED 1 - -#define FRUIT_HAS_DECLSPEC_DEPRECATED 0 - -#define FRUIT_HAS_MSVC_ASSUME 0 - -#define FRUIT_HAS_BUILTIN_UNREACHABLE 1 - -#endif // FRUIT_CONFIG_BASE_H diff --git a/configuration/bazel/gcc_attribute_deprecated.cpp b/configuration/bazel/gcc_attribute_deprecated.cpp new file mode 100644 index 0000000..6d0bf5f --- /dev/null +++ b/configuration/bazel/gcc_attribute_deprecated.cpp @@ -0,0 +1,5 @@ +void f() __attribute__((deprecated)); + +int main() { + return 0; +} diff --git a/configuration/bazel/has_trivial_copy.cpp b/configuration/bazel/has_trivial_copy.cpp new file mode 100644 index 0000000..b9da7d1 --- /dev/null +++ b/configuration/bazel/has_trivial_copy.cpp @@ -0,0 +1,5 @@ +int main() { + bool b = __has_trivial_copy(int); + (void) b; + return 0; +} diff --git a/configuration/bazel/is_trivially_copyable.cpp b/configuration/bazel/is_trivially_copyable.cpp new file mode 100644 index 0000000..b8b7379 --- /dev/null +++ b/configuration/bazel/is_trivially_copyable.cpp @@ -0,0 +1,5 @@ +int main() { + bool b = __is_trivially_copyable(int); + (void) b; + return 0; +} diff --git a/configuration/bazel/max_align_t.cpp b/configuration/bazel/max_align_t.cpp new file mode 100644 index 0000000..37342f1 --- /dev/null +++ b/configuration/bazel/max_align_t.cpp @@ -0,0 +1,5 @@ +#include +using X = max_align_t; +int main() { + return 0; +} diff --git a/configuration/bazel/msvc_assume.cpp b/configuration/bazel/msvc_assume.cpp new file mode 100644 index 0000000..cd9f6ed --- /dev/null +++ b/configuration/bazel/msvc_assume.cpp @@ -0,0 +1,13 @@ +int f() { + static int x = 1; + if (x == 1) { + return 0; + } else { + __assume(0); + // Note: the lack of return here is intentional + } +} + +int main() { + return f(); +} diff --git a/configuration/bazel/std_is_trivially_copy_constructible.cpp b/configuration/bazel/std_is_trivially_copy_constructible.cpp new file mode 100644 index 0000000..7cb8d5b --- /dev/null +++ b/configuration/bazel/std_is_trivially_copy_constructible.cpp @@ -0,0 +1,6 @@ +#include +int main() { + bool b = std::is_trivially_copy_constructible::value; + (void) b; + return 0; +} diff --git a/configuration/bazel/std_is_trivially_copyable.cpp b/configuration/bazel/std_is_trivially_copyable.cpp new file mode 100644 index 0000000..871b793 --- /dev/null +++ b/configuration/bazel/std_is_trivially_copyable.cpp @@ -0,0 +1,6 @@ +#include +int main() { + bool b = std::is_trivially_copyable::value; + (void) b; + return 0; +} diff --git a/configuration/bazel/std_max_align_t.cpp b/configuration/bazel/std_max_align_t.cpp new file mode 100644 index 0000000..acec695 --- /dev/null +++ b/configuration/bazel/std_max_align_t.cpp @@ -0,0 +1,5 @@ +#include +using X = std::max_align_t; +int main() { + return 0; +} diff --git a/configuration/bazel/typeid.cpp b/configuration/bazel/typeid.cpp new file mode 100644 index 0000000..9621d03 --- /dev/null +++ b/configuration/bazel/typeid.cpp @@ -0,0 +1,5 @@ +#include +int main() { + (void) typeid(int); + return 0; +} -- cgit v1.2.3 From 577949f73e6a6fd33407611afb3cd8b59ed13bac Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 9 Aug 2020 12:18:19 -0700 Subject: Move the bazel WORKSPACE file to the root dir, and replace the one in extras/bazel_root/ with a symlink. --- WORKSPACE | 18 ++++++++++++++++++ extras/bazel_root/WORKSPACE | 19 +------------------ 2 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 WORKSPACE mode change 100644 => 120000 extras/bazel_root/WORKSPACE diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..d74dafe --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,18 @@ +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "com_google_googletest", + remote = "https://github.com/google/googletest", + # GTest HEAD as of August 2018. + commit = "9c96f500a39df6915f8f1ab53b60be9889f1572b", +) + +git_repository( + name = "com_github_nelhage_rules_boost", + commit = "1e3a69bf2d5cd10c34b74f066054cd335d033d71", + remote = "https://github.com/nelhage/rules_boost", + shallow_since = "1591047380 -0700", +) + +load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") +boost_deps() diff --git a/extras/bazel_root/WORKSPACE b/extras/bazel_root/WORKSPACE deleted file mode 100644 index d74dafe..0000000 --- a/extras/bazel_root/WORKSPACE +++ /dev/null @@ -1,18 +0,0 @@ -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") - -git_repository( - name = "com_google_googletest", - remote = "https://github.com/google/googletest", - # GTest HEAD as of August 2018. - commit = "9c96f500a39df6915f8f1ab53b60be9889f1572b", -) - -git_repository( - name = "com_github_nelhage_rules_boost", - commit = "1e3a69bf2d5cd10c34b74f066054cd335d033d71", - remote = "https://github.com/nelhage/rules_boost", - shallow_since = "1591047380 -0700", -) - -load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") -boost_deps() diff --git a/extras/bazel_root/WORKSPACE b/extras/bazel_root/WORKSPACE new file mode 120000 index 0000000..6991d20 --- /dev/null +++ b/extras/bazel_root/WORKSPACE @@ -0,0 +1 @@ +../../WORKSPACE \ No newline at end of file -- cgit v1.2.3 From f83a61fa1f58e4bba0fbf68fa5e70eb9d6c85314 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 9 Aug 2020 12:22:36 -0700 Subject: Revert "Move the bazel WORKSPACE file to the root dir, and replace the one in extras/bazel_root/ with a symlink." This reverts commit 577949f73e6a6fd33407611afb3cd8b59ed13bac. --- WORKSPACE | 18 ------------------ extras/bazel_root/WORKSPACE | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 19 deletions(-) delete mode 100644 WORKSPACE mode change 120000 => 100644 extras/bazel_root/WORKSPACE diff --git a/WORKSPACE b/WORKSPACE deleted file mode 100644 index d74dafe..0000000 --- a/WORKSPACE +++ /dev/null @@ -1,18 +0,0 @@ -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") - -git_repository( - name = "com_google_googletest", - remote = "https://github.com/google/googletest", - # GTest HEAD as of August 2018. - commit = "9c96f500a39df6915f8f1ab53b60be9889f1572b", -) - -git_repository( - name = "com_github_nelhage_rules_boost", - commit = "1e3a69bf2d5cd10c34b74f066054cd335d033d71", - remote = "https://github.com/nelhage/rules_boost", - shallow_since = "1591047380 -0700", -) - -load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") -boost_deps() diff --git a/extras/bazel_root/WORKSPACE b/extras/bazel_root/WORKSPACE deleted file mode 120000 index 6991d20..0000000 --- a/extras/bazel_root/WORKSPACE +++ /dev/null @@ -1 +0,0 @@ -../../WORKSPACE \ No newline at end of file diff --git a/extras/bazel_root/WORKSPACE b/extras/bazel_root/WORKSPACE new file mode 100644 index 0000000..d74dafe --- /dev/null +++ b/extras/bazel_root/WORKSPACE @@ -0,0 +1,18 @@ +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "com_google_googletest", + remote = "https://github.com/google/googletest", + # GTest HEAD as of August 2018. + commit = "9c96f500a39df6915f8f1ab53b60be9889f1572b", +) + +git_repository( + name = "com_github_nelhage_rules_boost", + commit = "1e3a69bf2d5cd10c34b74f066054cd335d033d71", + remote = "https://github.com/nelhage/rules_boost", + shallow_since = "1591047380 -0700", +) + +load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") +boost_deps() -- cgit v1.2.3 From 6f3760672a0d2c772306e737d894a2ae2d8c5f58 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 9 Aug 2020 12:30:58 -0700 Subject: Add some example code to show how to depend on Fruit from a bazel project. --- .gitignore | 1 + extras/bazel_usage_example/BUILD | 8 ++++++ extras/bazel_usage_example/WORKSPACE | 19 +++++++++++++ extras/bazel_usage_example/main.cpp | 55 ++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 extras/bazel_usage_example/BUILD create mode 100644 extras/bazel_usage_example/WORKSPACE create mode 100644 extras/bazel_usage_example/main.cpp diff --git a/.gitignore b/.gitignore index 098e886..2a2e921 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ bench_results /*.vcxproj.user /out/build/x64-Debug /out/build/x64-Debug cxx-17 +/extras/bazel_usage_example/bazel-* diff --git a/extras/bazel_usage_example/BUILD b/extras/bazel_usage_example/BUILD new file mode 100644 index 0000000..47934aa --- /dev/null +++ b/extras/bazel_usage_example/BUILD @@ -0,0 +1,8 @@ + +licenses(["notice"]) + +cc_binary( + name = "hello_world", + srcs = ["main.cpp"], + deps = ["@com_google_fruit//third_party/fruit"], +) diff --git a/extras/bazel_usage_example/WORKSPACE b/extras/bazel_usage_example/WORKSPACE new file mode 100644 index 0000000..e037168 --- /dev/null +++ b/extras/bazel_usage_example/WORKSPACE @@ -0,0 +1,19 @@ +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "com_github_nelhage_rules_boost", + branch = "master", + remote = "https://github.com/nelhage/rules_boost", +) + +load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") +boost_deps() + +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "com_google_fruit", + remote = "https://github.com/google/fruit", + branch = "master", + strip_prefix = "extras/bazel_root", +) diff --git a/extras/bazel_usage_example/main.cpp b/extras/bazel_usage_example/main.cpp new file mode 100644 index 0000000..4364993 --- /dev/null +++ b/extras/bazel_usage_example/main.cpp @@ -0,0 +1,55 @@ + +#include +#include + +using fruit::Component; +using fruit::Injector; + +class Writer { +public: + virtual void write(std::string s) = 0; +}; + +class StdoutWriter : public Writer { +public: + // Like "StdoutWriter() = default;" but also marks this constructor as the + // one to use for injection. + INJECT(StdoutWriter()) = default; + + virtual void write(std::string s) override { + std::cout << s; + } +}; + +class Greeter { +public: + virtual void greet() = 0; +}; + +class GreeterImpl : public Greeter { +private: + Writer* writer; + +public: + // Like "GreeterImpl(Writer* writer) {...}" but also marks this constructor + // as the one to use for injection. + INJECT(GreeterImpl(Writer* writer)) : writer(writer) {} + + virtual void greet() override { + writer->write("Hello world!\n"); + } +}; + +Component getGreeterComponent() { + return fruit::createComponent().bind().bind(); +} + +int main() { + + Injector injector(getGreeterComponent); + Greeter* greeter = injector.get(); + + greeter->greet(); + + return 0; +} -- cgit v1.2.3 From c6d389dab4bcdb61ed1a3d9d0500f8d6feca1ecf Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 9 Aug 2020 21:10:16 -0700 Subject: Fix bazel build errors introduced by 94cefefb42f3685c1d64664e6aa9cbaf834b25ee when the Fruit headers are not also installed on the system where bazel runs. --- BUILD | 5 +++-- configuration/bazel/BUILD | 2 +- configuration/bazel/build_defs.bzl | 28 +++++++++++++++++++++++----- tests/BUILD | 5 ++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/BUILD b/BUILD index 4c2aef5..d93719c 100644 --- a/BUILD +++ b/BUILD @@ -7,7 +7,7 @@ filegroup( srcs = glob([ "include/**/*.h", ]) + [ - "//third_party/fruit/configuration/bazel:fruit_config", + "//third_party/fruit/configuration/bazel:fruit-config-base", ], ) @@ -16,11 +16,12 @@ cc_library( srcs = glob([ "src/*.cpp", "include/fruit/impl/**/*.h", - ]) + ["//third_party/fruit/configuration/bazel:fruit_config"], + ]), hdrs = glob(["include/fruit/*.h"]), includes = ["include", "configuration/bazel"], deps = [ "@boost//:unordered", + "//third_party/fruit/configuration/bazel:fruit-config-base", ], linkopts = ["-lm"], ) diff --git a/configuration/bazel/BUILD b/configuration/bazel/BUILD index 112b732..a207462 100644 --- a/configuration/bazel/BUILD +++ b/configuration/bazel/BUILD @@ -3,6 +3,6 @@ load("//third_party/fruit/configuration/bazel:build_defs.bzl", "generate_fruit_c package(default_visibility = ["//third_party/fruit:__subpackages__"]) generate_fruit_config( - name = "fruit_config", + name = "fruit-config-base", check_sources = glob(["*.cpp"]) ) diff --git a/configuration/bazel/build_defs.bzl b/configuration/bazel/build_defs.bzl index 8d683c4..28c3b17 100644 --- a/configuration/bazel/build_defs.bzl +++ b/configuration/bazel/build_defs.bzl @@ -17,7 +17,9 @@ def _generate_fruit_config_impl(ctx): check_output_files = [] for check_source in ctx.files.check_sources: - output_file = ctx.actions.declare_file(check_source.path + ".o") + check_name = check_source.path[:-len(".cpp")].split('/')[-1].split('\\')[-1] + + output_file = ctx.actions.declare_file(check_name + ".o") c_compile_variables = cc_common.create_compile_variables( feature_configuration = feature_configuration, @@ -37,9 +39,8 @@ def _generate_fruit_config_impl(ctx): variables = c_compile_variables, ) - check_name = check_source.path.split('/')[-1].split('\\')[-1] check_define = 'FRUIT_HAS_%s' % check_name.upper() - check_output_file = ctx.actions.declare_file(check_source.path + ".h") + check_output_file = ctx.actions.declare_file(check_name + ".h") ctx.actions.run_shell( command = '"$@" &>/dev/null && echo "#define %s 1" >"%s" || echo "#define %s 0" >"%s"; touch "%s"' % ( @@ -55,7 +56,7 @@ def _generate_fruit_config_impl(ctx): ) check_output_files.append(check_output_file) - merged_output_file = ctx.actions.declare_file(ctx.label.name + ".h") + merged_output_file = ctx.actions.declare_file("fruit/impl/fruit-config-base.h") ctx.actions.run_shell( command = '\n'.join([ '(', @@ -70,8 +71,25 @@ def _generate_fruit_config_impl(ctx): outputs = [merged_output_file], ) + compilation_context, compilation_outputs = cc_common.compile( + actions = ctx.actions, + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + public_hdrs = [merged_output_file], + name = "%s_link" % ctx.label.name, + ) + + linking_context, linking_outputs = cc_common.create_linking_context_from_compilation_outputs( + actions = ctx.actions, + feature_configuration = feature_configuration, + compilation_outputs = compilation_outputs, + cc_toolchain = cc_toolchain, + name = "%s_link" % ctx.label.name, + ) + return [ - DefaultInfo(files = depset([merged_output_file])), + DefaultInfo(files = depset([merged_output_file]), runfiles = ctx.runfiles(files = [merged_output_file])), + CcInfo(compilation_context=compilation_context, linking_context=linking_context), ] generate_fruit_config = rule( diff --git a/tests/BUILD b/tests/BUILD index b7ff089..e89f144 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -69,7 +69,6 @@ genrule( ], visibility = ["//third_party/fruit/tests:__subpackages__"], cmd = "" - + "FRUIT_HEADERS_LOCATION=`for f in $(locations //third_party/fruit:fruit_headers); do echo \"$$f\"; done | fgrep configuration/bazel/ | head -n 1 | sed 's|configuration/bazel/.*|./|'`;" + "TEST_HEADERS_LOCATION=`for f in $(locations :test_headers_filegroup); do echo \"$$f\"; done | fgrep test_macros.h | sed 's|test_macros.h|./|'`;" + "LIBFRUIT_LOCATION=`for f in $(locations //third_party/fruit); do echo \"$$f\"; done | fgrep libfruit.so | head -n 1 | sed 's|libfruit.so|./|'`;" + "LIBTEST_HEADERS_LOCATION=`for f in $(locations //third_party/fruit/tests:test_headers); do echo \"$$f\"; done | fgrep libtest_headers.so | head -n 1 | sed 's|libtest_headers.so|./|'`;" @@ -86,8 +85,8 @@ genrule( + "PATH_TO_COMPILED_FRUIT_LIB='third_party/fruit/tests'\n" + "PATH_TO_COMPILED_TEST_HEADERS='third_party/fruit/tests/test_headers'\n" + "PATH_TO_COMPILED_TEST_HEADERS_LIB='third_party/fruit/tests/test_headers'\n" - + "PATH_TO_FRUIT_STATIC_HEADERS='$${FRUIT_HEADERS_LOCATION}/include'\n" - + "PATH_TO_FRUIT_GENERATED_HEADERS='$${FRUIT_HEADERS_LOCATION}/configuration/bazel'\n" + + "PATH_TO_FRUIT_STATIC_HEADERS='third_party/fruit/include'\n" + + "PATH_TO_FRUIT_GENERATED_HEADERS='third_party/fruit/configuration/bazel'\n" + "PATH_TO_FRUIT_TEST_HEADERS='$${TEST_HEADERS_LOCATION}'\n" + "ADDITIONAL_LINKER_FLAGS='-lstdc++ -lm'\n" + "RUN_TESTS_UNDER_VALGRIND='0'\n" -- cgit v1.2.3 From 928458857f4b85a0016c2d724486343b4660cb46 Mon Sep 17 00:00:00 2001 From: Marco Poletti Date: Sun, 20 Sep 2020 12:04:41 -0700 Subject: Support non-assignable (but movable) types in factory arguments when using registerFactory. --- include/fruit/impl/component_functors.defn.h | 8 +-- tests/test_register_factory.py | 73 ++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/include/fruit/impl/component_functors.defn.h b/include/fruit/impl/component_functors.defn.h index 83ef385..e6778b1 100644 --- a/include/fruit/impl/component_functors.defn.h +++ b/include/fruit/impl/component_functors.defn.h @@ -402,7 +402,7 @@ template struct GetAssistedArg> { template inline Arg operator()(InjectedArgsTuple&, UserProvidedArgsTuple& user_provided_args) { - return std::get(user_provided_args); + return std::move(std::get(user_provided_args)); } }; @@ -437,9 +437,9 @@ struct RegisterFactoryHelper { using Result = Eval; void operator()(FixedSizeVector& entries) { auto function_provider = [](NakedInjectedArgs... args) { - auto injected_args = std::make_tuple(args...); - auto object_provider = [injected_args](NakedUserProvidedArgs... params) mutable { - auto user_provided_args = std::tie(params...); + std::tuple injected_args{args...}; + auto object_provider = [=](NakedUserProvidedArgs... params) mutable { + std::tuple user_provided_args{std::move(params)...}; // These are unused if they are 0-arg tuples. Silence the unused-variable warnings anyway. (void)injected_args; (void)user_provided_args; diff --git a/tests/test_register_factory.py b/tests/test_register_factory.py index 202d18b..8f62946 100755 --- a/tests/test_register_factory.py +++ b/tests/test_register_factory.py @@ -2005,6 +2005,79 @@ class TestRegisterFactory(parameterized.TestCase): source, locals()) + @multiple_parameters([ + ('X()', 'X'), + ('std::unique_ptr(new X())', 'std::unique_ptr'), + ], [ + 'WithNoAnnotation', + 'WithAnnotation1', + ]) + def test_register_factory_with_non_assignable_injected_param_success(self, ConstructX, XPtr, WithAnnot): + source = ''' + struct Y { + Y(const Y&) = delete; + Y& operator=(const Y&) = delete; + + Y() = default; + Y(Y&&) = default; + Y& operator=(Y&&) = default; + }; + struct X {}; + + fruit::Component> getYComponent() { + return fruit::createComponent() + .registerConstructor()>(); + } + + fruit::Component> getComponent() { + return fruit::createComponent() + .install(getYComponent) + .registerFactory)>([](Y&){ return ConstructX; }); + } + + int main() { + fruit::Injector> injector(getComponent); + XPtr x = injector.get>()(); + (void) x; + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + + @multiple_parameters([ + ('X()', 'X'), + ('std::unique_ptr(new X())', 'std::unique_ptr'), + ]) + def test_register_factory_with_non_assignable_assisted_param_success(self, ConstructX, XPtr): + source = ''' + struct Y { + Y(const Y&) = delete; + Y& operator=(const Y&) = delete; + + Y() = default; + Y(Y&&) = default; + Y& operator=(Y&&) = default; + }; + struct X {}; + + fruit::Component> getComponent() { + return fruit::createComponent() + .registerFactory)>([](Y){ return ConstructX; }); + } + + int main() { + fruit::Injector> injector(getComponent); + XPtr x = injector.get>()(Y()); + (void) x; + } + ''' + expect_success( + COMMON_DEFINITIONS, + source, + locals()) + def test_register_factory_requiring_nonconst_then_requiring_const_ok(self): source = ''' struct X {}; -- cgit v1.2.3