diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6a2b1061ad..06c2d742e3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -556,8 +556,25 @@ if (TARGET TBB::tbb) tbb_add_test(SUBDIR tbb NAME test_tbb_fork DEPENDENCIES TBB::tbb) endif() - tbb_add_test(SUBDIR tbb NAME test_tbb_header DEPENDENCIES TBB::tbb) + tbb_add_test(SUBDIR tbb NAME test_tbb_header DEPENDENCIES TBB::tbb TBB::tbbmalloc) target_sources(test_tbb_header PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tbb/test_tbb_header_secondary.cpp) + + if (TBB_TEST_CXX20_MODULES) + if (CMAKE_VERSION VERSION_LESS 3.28) + message(WARNING "CMake 3.28 or higher is required to use C++20 modules, skipping module test") + elseif (NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 20) + message(WARNING "C++ standard 20 or higher is required, skipping module test") + else() + tbb_add_test(SUBDIR tbb NAME test_tbb_header_module_consumer DEPENDENCIES TBB::tbb TBB::tbbmalloc) + target_sources(test_tbb_header_module_consumer + PUBLIC FILE_SET CXX_MODULES FILES + ${CMAKE_CURRENT_SOURCE_DIR}/tbb/test_tbb_header_module.cppm) + set_target_properties(test_tbb_header_module_consumer PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON) + endif() + endif() + if (NOT MINGW AND TBB_OPENMP_FLAG AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "(mips)") tbb_add_test(SUBDIR tbb NAME test_openmp DEPENDENCIES TBB::tbb) diff --git a/test/tbb/test_tbb_header.cpp b/test/tbb/test_tbb_header.cpp index ad782323c4..b5e0175cd6 100644 --- a/test/tbb/test_tbb_header.cpp +++ b/test/tbb/test_tbb_header.cpp @@ -1,6 +1,6 @@ /* Copyright (c) 2005-2025 Intel Corporation - Copyright (c) 2025 UXL Foundation Contributors + Copyright (c) 2025-2026 UXL Foundation Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,6 +25,8 @@ Most of the checks happen at the compilation or link phases. **/ +#if !__TBB_TEST_MODULE_EXPORT + #if __INTEL_COMPILER && _MSC_VER #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated #endif @@ -92,8 +94,13 @@ #include "common/test.h" #endif -static volatile size_t g_sink; +#endif /* !__TBB_TEST_MODULE_EXPORT */ +#if __TBB_TEST_MODULE_EXPORT +inline volatile size_t g_sink; +#else +static volatile size_t g_sink; +#endif /* __TBB_TEST_MODULE_EXPORT */ #define TestTypeDefinitionPresence( Type ) g_sink = sizeof(tbb::Type); #define TestTypeDefinitionPresence2(TypeStart, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeEnd); #define TestTypeDefinitionPresence3(TypeStart, TypeMid, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeMid,TypeEnd); @@ -114,6 +121,9 @@ struct Body1b { // binary operator for reduction struct Body1bc { // binary operator for comparison bool operator() (const int, const int) const { return false; } }; +struct Body1c { // body for function_node + int operator() ( int ) const { return 0; } +}; struct Body2 { Body2 () {} Body2 ( const Body2&, tbb::split ) {} @@ -135,10 +145,15 @@ struct Body3a { // for lambda-friednly parallel_scan int operator() ( const tbb::blocked_range&, const int, bool ) const { return 0; } }; struct Msg {}; +struct SuspendBody { + void operator()(tbb::task::suspend_point) const {} +}; // Test if all the necessary symbols are exported for the exceptions thrown by TBB. // Missing exports result either in link error or in runtime assertion failure. +#if !__TBB_TEST_MODULE_EXPORT #include +#endif template void TestExceptionClassExports ( const E& exc, tbb::detail::exception_id eid ) { @@ -163,7 +178,11 @@ void TestExceptionClassExports ( const E& exc, tbb::detail::exception_id eid ) { #endif /* TBB_USE_EXCEPTIONS */ } +#if __TBB_TEST_MODULE_EXPORT +inline void TestExceptionClassesExports () { +#else static void TestExceptionClassesExports () { +#endif TestExceptionClassExports( std::bad_alloc(), tbb::detail::exception_id::bad_alloc ); TestExceptionClassExports( tbb::bad_last_alloc(), tbb::detail::exception_id::bad_last_alloc ); TestExceptionClassExports( std::invalid_argument("test"), tbb::detail::exception_id::nonpositive_step ); @@ -180,7 +199,11 @@ static void TestExceptionClassesExports () { #if __TBB_CPF_BUILD // These names are only tested in "preview" configuration // When a feature becomes fully supported, its names should be moved to the main test +#if __TBB_TEST_MODULE_EXPORT +inline void TestPreviewNames() { +#else static void TestPreviewNames() { +#endif TestTypeDefinitionPresence2( concurrent_lru_cache ); TestTypeDefinitionPresence( isolated_task_group ); #if TBB_PREVIEW_MEMORY_POOL @@ -188,10 +211,24 @@ static void TestPreviewNames() { TestTypeDefinitionPresence( memory_pool> ); TestTypeDefinitionPresence( fixed_pool ); #endif +#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS + TestTypeDefinitionPresence( task_completion_handle ); + TestFuncDefinitionPresence( is_inside_task, (), bool ); +#endif +#if __TBB_PREVIEW_PARALLEL_PHASE + TestTypeDefinitionPresence( task_arena::leave_policy ); + TestTypeDefinitionPresence( task_arena::scoped_parallel_phase ); + TestFuncDefinitionPresence( this_task_arena::start_parallel_phase, (), void ); + TestFuncDefinitionPresence( this_task_arena::end_parallel_phase, (bool), void ); +#endif } #endif +#if __TBB_TEST_MODULE_EXPORT +export inline void DefinitionPresence() { +#else static void DefinitionPresence() { +#endif TestTypeDefinitionPresence( ext::assertion_handler_type ); TestTypeDefinitionPresence( cache_aligned_allocator ); TestTypeDefinitionPresence( tbb_hash_compare ); @@ -210,6 +247,10 @@ static void DefinitionPresence() { TestTypeDefinitionPresence( concurrent_vector ); TestTypeDefinitionPresence( combinable ); TestTypeDefinitionPresence( enumerable_thread_specific ); + /* TLS names */ + TestTypeDefinitionPresence( flattened2d>> ); + TestTypeDefinitionPresence( ets_key_usage_type ); + TestFuncDefinitionPresence( flatten2d, (const tbb::enumerable_thread_specific>&), tbb::flattened2d>> ); TestFuncDefinitionPresence( ext::get_assertion_handler, (), tbb::ext::assertion_handler_type ); TestFuncDefinitionPresence( ext::set_assertion_handler, @@ -240,6 +281,12 @@ static void DefinitionPresence() { TestTypeDefinitionPresence( flow::limiter_node ); TestTypeDefinitionPresence2(flow::indexer_node ); TestTypeDefinitionPresence2(flow::composite_node, std::tuple > ); + TestTypeDefinitionPresence( flow::graph_node ); + TestTypeDefinitionPresence( flow::reset_flags ); + TestTypeDefinitionPresence( flow::tag_value ); + TestTypeDefinitionPresence( flow::node_priority_t ); + TestFuncDefinitionPresence( flow::copy_body, (tbb::flow::function_node&), Body1c ); + TestFuncDefinitionPresence( flow::cast_to, (tbb::flow::tagged_msg const&), const int& ); /* Mutex names */ TestTypeDefinitionPresence( null_mutex ); TestTypeDefinitionPresence( null_rw_mutex ); @@ -259,6 +306,8 @@ static void DefinitionPresence() { TestTypeDefinitionPresence( blocked_range3d ); TestTypeDefinitionPresence2( blocked_nd_range ); TestTypeDefinitionPresence( collaborative_once_flag ); + TestTypeDefinitionPresence( filter_mode ); + TestTypeDefinitionPresence( flow_control ); TestFuncDefinitionPresence( collaborative_call_once, (tbb::collaborative_once_flag&, const Body&), void ); TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, const Body&), void ); TestFuncDefinitionPresence( parallel_for_each, (int*, int*, const Body1&), void ); @@ -288,13 +337,42 @@ static void DefinitionPresence() { TestTypeDefinitionPresence( task_arena ); TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int ); TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int ); + TestFuncDefinitionPresence( this_task_arena::isolate, (Body&&), void ); + TestFuncDefinitionPresence( this_task_arena::enqueue, (tbb::task_handle&&), void ); + TestFuncDefinitionPresence( this_task_arena::enqueue, (Body&&), void ); + TestFuncDefinitionPresence( this_task_arena::enqueue, (Body&&, tbb::task_group&), void ); + TestFuncDefinitionPresence( create_numa_task_arenas, (tbb::task_arena::constraints, unsigned), std::vector ); + TestTypeDefinitionPresence( core_type_id ); + TestFuncDefinitionPresence( info::core_types, (), std::vector ); TestFuncDefinitionPresence( info::numa_nodes, (), std::vector ); TestFuncDefinitionPresence( info::default_concurrency, (tbb::numa_node_id), int ); TestTypeDefinitionPresence( task_scheduler_observer ); TestTypeDefinitionPresence( tbb_allocator ); TestTypeDefinitionPresence( tick_count ); TestTypeDefinitionPresence( global_control ); + TestTypeDefinitionPresence( task_scheduler_handle ); + TestFuncDefinitionPresence( finalize, (tbb::task_scheduler_handle&, const std::nothrow_t&), bool ); +#if TBB_USE_EXCEPTIONS + TestFuncDefinitionPresence( finalize, (tbb::task_scheduler_handle&), void ); +#endif TestTypeDefinitionPresence( scalable_allocator ); + TestTypeDefinitionPresence( attach ); +#if __TBB_CPP17_MEMORY_RESOURCE_PRESENT + /* Allocator resource names */ + TestTypeDefinitionPresence( cache_aligned_resource ); + TestFuncDefinitionPresence( scalable_memory_resource, (), std::pmr::memory_resource* ); +#endif + /* Task group names */ + TestTypeDefinitionPresence( task_group_status ); + TestFuncDefinitionPresence( is_current_task_group_canceling, (), bool ); + TestTypeDefinitionPresence( task_handle ); + /* Task names */ + TestFuncDefinitionPresence( task::current_context, (), tbb::task_group_context* ); +#if __TBB_RESUMABLE_TASKS + TestTypeDefinitionPresence( task::suspend_point ); + TestFuncDefinitionPresence( task::resume, (tbb::task::suspend_point), void ); + TestFuncDefinitionPresence( task::suspend, (SuspendBody), void ); +#endif #if __TBB_CPF_BUILD TestPreviewNames(); @@ -309,6 +387,7 @@ static void DefinitionPresence() { TestExceptionClassesExports(); } +#if !__TBB_TEST_MODULE_EXPORT #if __TBB_TEST_SECONDARY /* This mode is used to produce a secondary object file that is linked with the main one in order to detect "multiple definition" linker error. @@ -330,3 +409,4 @@ TEST_CASE("Test for multiple definition linker error") { Secondary(); } #endif +#endif /* !__TBB_TEST_MODULE_EXPORT */ diff --git a/test/tbb/test_tbb_header_module.cppm b/test/tbb/test_tbb_header_module.cppm new file mode 100644 index 0000000000..f30166384f --- /dev/null +++ b/test/tbb/test_tbb_header_module.cppm @@ -0,0 +1,47 @@ +/* + Copyright (c) 2026 UXL Foundation Contributors + + 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. +*/ + +//! \file test_tbb_header_module.cppm +//! \brief C++20 module interface unit to test TBB public API for TU-local entity exposure +module; +// Preprocessing macros from test_tbb_header.cpp +#if __INTEL_COMPILER && _MSC_VER +#pragma warning(disable : 2586) // decorated name length exceeded, name was truncated +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#define __TBB_NO_IMPLICIT_LINKAGE 1 +#define __TBB_TEST_MODULE_EXPORT 1 + +#define CHECK(x) do { if (!(x)) { std::terminate(); } } while (false) +#define CHECK_MESSAGE(x, y) CHECK(x); + +#include "common/config.h" +#include "oneapi/tbb/detail/_config.h" +#include "tbb/tbb.h" + +#include +#include +#include +#include +#include + +export module tbb_header_test; + +#include "test_tbb_header.cpp" diff --git a/test/tbb/test_tbb_header_module_consumer.cpp b/test/tbb/test_tbb_header_module_consumer.cpp new file mode 100644 index 0000000000..442b8ebe34 --- /dev/null +++ b/test/tbb/test_tbb_header_module_consumer.cpp @@ -0,0 +1,26 @@ +/* + Copyright (c) 2026 UXL Foundation Contributors + + 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. +*/ + +//! \file test_tbb_header_module_consumer.cpp +//! \brief Test for [all] specification using C++20 modules + +#include "common/test.h" +import tbb_header_test; + +//! \brief \ref interface +TEST_CASE("Test for definition presence in module interface") { + DefinitionPresence(); +}