From b9f47e0119eee789ca4bb80fce59b8200c09ea12 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 18 Jul 2025 15:44:00 -0400 Subject: [PATCH 01/11] Add is_sync_call() to eosio::contract class --- libraries/eosiolib/contracts/eosio/contract.hpp | 15 ++++++++++++++- tools/include/eosio/codegen.hpp | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/contract.hpp b/libraries/eosiolib/contracts/eosio/contract.hpp index d60d47241c..15e4f0fda9 100644 --- a/libraries/eosiolib/contracts/eosio/contract.hpp +++ b/libraries/eosiolib/contracts/eosio/contract.hpp @@ -35,8 +35,9 @@ class contract { * @param self - The name of the account this contract is deployed on * @param first_receiver - The account the incoming action was first received at. * @param ds - The datastream used + * @param is_call - This contract is created for a sync call */ - contract( name self, name first_receiver, datastream ds ):_self(self),_first_receiver(first_receiver),_ds(ds) {} + contract( name self, name first_receiver, datastream ds, bool is_call = false ):_self(self),_first_receiver(first_receiver),_ds(ds),_is_call(is_call) {} /** * @@ -75,6 +76,13 @@ class contract { */ inline const datastream& get_datastream()const { return _ds; } + /** + * Whether this contract is created for a sync call + * + * @return bool - Whether this contract is created for a sync call + */ + inline bool is_sync_call()const { return _is_call; } + protected: /** * The name of the account this contract is deployed on. @@ -90,5 +98,10 @@ class contract { * The datastream for this contract */ datastream _ds = datastream(nullptr, 0); + + /** + * The indication whether the contract is created for sync call or not + */ + bool _is_call = false; }; } diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index 44ed8e0a1f..aa8925bfbf 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -261,7 +261,8 @@ namespace eosio { namespace cdt { i++; } const auto& call_function = [&]() { - ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{receiver},eosio::name{receiver},ds}." << decl->getNameAsString() << "("; + // `true` indicates a sync call + ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{receiver},eosio::name{receiver},ds,true}." << decl->getNameAsString() << "("; for (int i=0; i < decl->parameters().size(); i++) { ss << "arg" << i; if (i < decl->parameters().size()-1) From 09b234bf35b99e84405a750de54608ae5802d2da Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 18 Jul 2025 15:44:45 -0400 Subject: [PATCH 02/11] Update sync_call_addr_book_callee for new eosio::contract constructor --- tests/unit/test_contracts/sync_call_addr_book_callee.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_contracts/sync_call_addr_book_callee.hpp b/tests/unit/test_contracts/sync_call_addr_book_callee.hpp index 0cde988ac1..1c8ba5f8ce 100644 --- a/tests/unit/test_contracts/sync_call_addr_book_callee.hpp +++ b/tests/unit/test_contracts/sync_call_addr_book_callee.hpp @@ -8,7 +8,7 @@ struct person_info { class [[eosio::contract]] sync_call_addr_book_callee : public eosio::contract { public: - sync_call_addr_book_callee(eosio::name receiver, eosio::name code, eosio::datastream ds): contract(receiver, code, ds) {} + sync_call_addr_book_callee(eosio::name receiver, eosio::name code, eosio::datastream ds, bool is_call = false): contract(receiver, code, ds, is_call) {} [[eosio::call]] void upsert(eosio::name user, std::string first_name, std::string street); From b086797420bfe1e7877aadd38f71a7a00b96dd81 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 18 Jul 2025 15:54:51 -0400 Subject: [PATCH 03/11] Add tests for is_sync_call() --- tests/integration/call_tests.cpp | 30 +++++++++++++++++-- .../unit/test_contracts/sync_call_callee.cpp | 3 ++ .../unit/test_contracts/sync_call_callee.hpp | 5 ++++ .../unit/test_contracts/sync_call_caller.cpp | 7 +++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/tests/integration/call_tests.cpp b/tests/integration/call_tests.cpp index be7562ed9c..feb102ef62 100644 --- a/tests/integration/call_tests.cpp +++ b/tests/integration/call_tests.cpp @@ -140,12 +140,11 @@ BOOST_AUTO_TEST_CASE(mixed_action_call_tags_test) { try { BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hstmulprmtst"_n, "caller"_n, {})); // Make sure we can push an action using `sum`. - //BOOST_REQUIRE_NO_THROW(t.push_action("callee"_n, "sum"_n, "callee"_n, - t.push_action("callee"_n, "sum"_n, "callee"_n, + BOOST_REQUIRE_NO_THROW(t.push_action("callee"_n, "sum"_n, "callee"_n, mvo() ("a", 1) ("b", 2) - ("c", 3)); //); + ("c", 3))); } FC_LOG_AND_RETHROW() } // Verify the receiver contract with only one sync call function works @@ -234,4 +233,29 @@ BOOST_AUTO_TEST_CASE(addr_book_tests) { try { BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "get"_n, "caller"_n, mvo() ("user", "alice"))); } FC_LOG_AND_RETHROW() } +// For a function tagged as both `action` and `call`, verify is_sync_call() +// returns true if tagged as `call` and false if tagged as `action`. +BOOST_AUTO_TEST_CASE(is_sync_call_test) { try { + call_tester t({ + {"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()}, + {"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()} + }); + + // issynccall() is tagged as both `action` and `call`, and returns + // is_sync_call(). makesynccall() calls issynccall() as a sync call + // and returns its result. So the current action return value must be + // true. + auto trx_trace = t.push_action("caller"_n, "makesynccall"_n, "caller"_n, {}); + auto& action_trace = trx_trace->action_traces[0]; + bool return_value = fc::raw::unpack(action_trace.return_value); + BOOST_REQUIRE(return_value == true); + + // Call issynccall() directly as an action. Since issynccall() + // returns is_sync_call(), the current action return value must be false. + trx_trace = t.push_action("callee"_n, "issynccall"_n, "callee"_n, {}); + auto& action_trace1 = trx_trace->action_traces[0]; + return_value = fc::raw::unpack(action_trace1.return_value); + BOOST_REQUIRE(return_value == false); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/sync_call_callee.cpp b/tests/unit/test_contracts/sync_call_callee.cpp index 867f67dd33..883d8a4e72 100644 --- a/tests/unit/test_contracts/sync_call_callee.cpp +++ b/tests/unit/test_contracts/sync_call_callee.cpp @@ -31,3 +31,6 @@ struct1_t sync_call_callee::pass_multi_structs(struct1_t s1, int32_t m, struct2_ return { .a = s1.a * m + s2.c, .b = s1.b * m + s2.d }; } +bool sync_call_callee::issynccall() { + return is_sync_call(); +} diff --git a/tests/unit/test_contracts/sync_call_callee.hpp b/tests/unit/test_contracts/sync_call_callee.hpp index fc867da405..2f5d5d414b 100644 --- a/tests/unit/test_contracts/sync_call_callee.hpp +++ b/tests/unit/test_contracts/sync_call_callee.hpp @@ -38,6 +38,11 @@ class [[eosio::contract]] sync_call_callee : public eosio::contract{ [[eosio::call]] struct1_t pass_multi_structs(struct1_t s1, int32_t m, struct2_t s2); + // return is_sync_call() + [[eosio::action, eosio::call]] + bool issynccall(); + using issynccall_func = eosio::call_wrapper<"issynccall"_i, &sync_call_callee::issynccall>; + using return_ten_func = eosio::call_wrapper<"return_ten"_i, &sync_call_callee::return_ten>; using echo_input_func = eosio::call_wrapper<"echo_input"_i, &sync_call_callee::echo_input>; using void_func_func = eosio::call_wrapper<"void_func"_i, &sync_call_callee::void_func>; diff --git a/tests/unit/test_contracts/sync_call_caller.cpp b/tests/unit/test_contracts/sync_call_caller.cpp index ad7c8d2d33..a97a78b74a 100644 --- a/tests/unit/test_contracts/sync_call_caller.cpp +++ b/tests/unit/test_contracts/sync_call_caller.cpp @@ -172,4 +172,11 @@ class [[eosio::contract]] sync_call_caller : public eosio::contract{ status = eosio::call("callee"_n, 0, bad_version_data.data(), bad_version_data.size()); eosio::check(status == -10000, "call did not return -10000 for invalid version"); } + + // Call issynccall as a sync call and return its return value + [[eosio::action]] + bool makesynccall() { + sync_call_callee::issynccall_func is_sync_call_func{ "callee"_n }; + return is_sync_call_func(); + } }; From db42ab457f67f92f016c4d33aaff6212195519cd Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 21 Jul 2025 15:08:17 -0400 Subject: [PATCH 04/11] Use set_exec_type() to explicitly set a contract's execution type (action or call) to prevent accidental errors by contract authors --- .../eosiolib/contracts/eosio/contract.hpp | 31 +++++++++--- .../sync_call_addr_book_callee.hpp | 2 +- tools/include/eosio/codegen.hpp | 50 +++++++++++++++++-- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/contract.hpp b/libraries/eosiolib/contracts/eosio/contract.hpp index 15e4f0fda9..81276d7afa 100644 --- a/libraries/eosiolib/contracts/eosio/contract.hpp +++ b/libraries/eosiolib/contracts/eosio/contract.hpp @@ -29,15 +29,19 @@ namespace eosio { */ class contract { public: + enum class exec_type_t : uint8_t { + action, + call + }; + /** * Construct a new contract given the contract name * * @param self - The name of the account this contract is deployed on * @param first_receiver - The account the incoming action was first received at. * @param ds - The datastream used - * @param is_call - This contract is created for a sync call */ - contract( name self, name first_receiver, datastream ds, bool is_call = false ):_self(self),_first_receiver(first_receiver),_ds(ds),_is_call(is_call) {} + contract( name self, name first_receiver, datastream ds ):_self(self),_first_receiver(first_receiver),_ds(ds) {} /** * @@ -77,13 +81,26 @@ class contract { inline const datastream& get_datastream()const { return _ds; } /** - * Whether this contract is created for a sync call + * Whether this contract is for a sync call + * + * @return bool - Whether this contract is for a sync call + */ + inline bool is_sync_call()const { + check(_exec_type.has_value(), "too early to call is_sync_call(). _exec_type has not been set yet"); + return (*_exec_type == exec_type_t::call); + } + + /** + * Set the exectution type. * - * @return bool - Whether this contract is created for a sync call + * @param type - The exectution type to be set. */ - inline bool is_sync_call()const { return _is_call; } + inline void set_exec_type(exec_type_t type) { + _exec_type = type; + } protected: + /** * The name of the account this contract is deployed on. */ @@ -100,8 +117,8 @@ class contract { datastream _ds = datastream(nullptr, 0); /** - * The indication whether the contract is created for sync call or not + * The execution type: action or sync call */ - bool _is_call = false; + std::optional _exec_type = std::nullopt; // use std::optional to prevent from being used before having value like in constructors }; } diff --git a/tests/unit/test_contracts/sync_call_addr_book_callee.hpp b/tests/unit/test_contracts/sync_call_addr_book_callee.hpp index 1c8ba5f8ce..0cde988ac1 100644 --- a/tests/unit/test_contracts/sync_call_addr_book_callee.hpp +++ b/tests/unit/test_contracts/sync_call_addr_book_callee.hpp @@ -8,7 +8,7 @@ struct person_info { class [[eosio::contract]] sync_call_addr_book_callee : public eosio::contract { public: - sync_call_addr_book_callee(eosio::name receiver, eosio::name code, eosio::datastream ds, bool is_call = false): contract(receiver, code, ds, is_call) {} + sync_call_addr_book_callee(eosio::name receiver, eosio::name code, eosio::datastream ds): contract(receiver, code, ds) {} [[eosio::call]] void upsert(eosio::name user, std::string first_name, std::string street); diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index aa8925bfbf..123ea3c631 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -146,11 +146,28 @@ namespace eosio { namespace cdt { return ""; } + // Return `true` if the method `decl`'s base class if `eosio::contract` + bool base_is_eosio_contract_class(const clang::CXXMethodDecl* decl) { + auto cxx_decl = decl->getParent(); + // on this point it could be just an attribute so let's check base classes + for (const auto& base : cxx_decl->bases()) { + if (const clang::Type *base_type = base.getType().getTypePtrOrNull()) { + if (const auto* cur_cxx_decl = base_type->getAsCXXRecordDecl()) { + if (cur_cxx_decl->getQualifiedNameAsString() == "eosio::contract") { + return true;; + } + } + } + } + return false; + } + template void create_dispatch(const std::string& attr, const std::string& func_name, F&& get_str, CXXMethodDecl* decl) { constexpr static uint32_t max_stack_size = 512; codegen& cg = codegen::get(); std::string nm = decl->getNameAsString()+"_"+decl->getParent()->getNameAsString(); + if (cg.is_eosio_contract(decl, cg.contract_name)) { ss << "\n\n#include \n"; ss << "#include \n"; @@ -190,8 +207,22 @@ namespace eosio { namespace cdt { ss << tn << " arg" << i << "; ds >> arg" << i << ";\n"; i++; } + + // Create contract object + ss << decl->getParent()->getQualifiedNameAsString() + << " obj {eosio::name{r},eosio::name{c},ds};\n"; + + // Call `set_exec_type()` only for contracts dervied from `eosio::contract`. + // A contract class can have only `eosio::contract` attribute + // but does not inherit from the `eosio::contract` class; + // it may not have `set_exec_type()`. We need to make sure the class derives + // from `eosio::contract` before calling set_exec_type(). + if (base_is_eosio_contract_class(decl)) { + ss << "obj.set_exec_type(eosio::contract::exec_type_t::action);\n"; + } + const auto& call_action = [&]() { - ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{r},eosio::name{c},ds}." << decl->getNameAsString() << "("; + ss << "obj." << decl->getNameAsString() << "("; for (int i=0; i < decl->parameters().size(); i++) { ss << "arg" << i; if (i < decl->parameters().size()-1) @@ -260,9 +291,22 @@ namespace eosio { namespace cdt { ss << tn << " arg" << i << "; ds >> arg" << i << ";\n"; i++; } + + // Create contract object + ss << decl->getParent()->getQualifiedNameAsString() + << " obj {eosio::name{receiver},eosio::name{receiver},ds};\n"; + + // Call `set_exec_type()` only for contracts dervied from `eosio::contract`. + // A contract class can have only `eosio::contract` attribute + // but does not inherit from the `eosio::contract` class; + // it may not have `set_exec_type()`. We need to make sure the class derives + // from `eosio::contract` before calling set_exec_type(). + if (base_is_eosio_contract_class(decl)) { + ss << "obj.set_exec_type(eosio::contract::exec_type_t::call);\n"; + } + const auto& call_function = [&]() { - // `true` indicates a sync call - ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{receiver},eosio::name{receiver},ds,true}." << decl->getNameAsString() << "("; + ss << "obj." << decl->getNameAsString() << "("; for (int i=0; i < decl->parameters().size(); i++) { ss << "arg" << i; if (i < decl->parameters().size()-1) From bad7b81900abef3cd5223437d1ebf5cbb8d678b4 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 21 Jul 2025 15:41:39 -0400 Subject: [PATCH 05/11] Do not use unnecessary and expensivestd::optional for _exec_type --- libraries/eosiolib/contracts/eosio/contract.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/contract.hpp b/libraries/eosiolib/contracts/eosio/contract.hpp index 81276d7afa..f0ef6e0568 100644 --- a/libraries/eosiolib/contracts/eosio/contract.hpp +++ b/libraries/eosiolib/contracts/eosio/contract.hpp @@ -31,7 +31,8 @@ class contract { public: enum class exec_type_t : uint8_t { action, - call + call, + unknown }; /** @@ -86,8 +87,8 @@ class contract { * @return bool - Whether this contract is for a sync call */ inline bool is_sync_call()const { - check(_exec_type.has_value(), "too early to call is_sync_call(). _exec_type has not been set yet"); - return (*_exec_type == exec_type_t::call); + check(_exec_type != exec_type_t::unknown, "too early to call is_sync_call(). _exec_type has not been set yet"); + return (_exec_type == exec_type_t::call); } /** @@ -119,6 +120,6 @@ class contract { /** * The execution type: action or sync call */ - std::optional _exec_type = std::nullopt; // use std::optional to prevent from being used before having value like in constructors + exec_type_t _exec_type = exec_type_t::unknown; }; } From a294a08ab742f4c10977da668125a091a211344d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 21 Jul 2025 15:46:46 -0400 Subject: [PATCH 06/11] Make separate_cpp_hpp derive publicly from eosio::contract such that set_exec_type() can be used --- tests/toolchain/build-pass/separate_cpp_hpp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/toolchain/build-pass/separate_cpp_hpp.hpp b/tests/toolchain/build-pass/separate_cpp_hpp.hpp index 2002834021..d1685a2858 100644 --- a/tests/toolchain/build-pass/separate_cpp_hpp.hpp +++ b/tests/toolchain/build-pass/separate_cpp_hpp.hpp @@ -1,6 +1,6 @@ #include -class [[eosio::contract]] separate_cpp_hpp : eosio::contract { +class [[eosio::contract]] separate_cpp_hpp : public eosio::contract { public: using contract::contract; From a53fc34ce35a5e535a30417759a366d5b547b44d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 21 Jul 2025 17:54:33 -0400 Subject: [PATCH 07/11] Fix action_wrapper fails to compile if it contains bool as the first argument due to ambiguity of partial specializations of is_same and is_same --- libraries/eosiolib/contracts/eosio/action.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/eosiolib/contracts/eosio/action.hpp b/libraries/eosiolib/contracts/eosio/action.hpp index d043931e25..a233a2275e 100644 --- a/libraries/eosiolib/contracts/eosio/action.hpp +++ b/libraries/eosiolib/contracts/eosio/action.hpp @@ -455,6 +455,11 @@ namespace eosio { template struct is_same { static constexpr bool value = std::is_integral::value; }; + // Full specialization to resolve ambiguity introduced by partial specializations + // of is_same and is_same + template <> + struct is_same { static constexpr bool value = true; }; + template struct get_nth_impl { static constexpr auto value = get_nth_impl::value; }; From 00cb3153963d1aaa1876473b1675d66973da93ea Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 22 Jul 2025 07:46:50 -0400 Subject: [PATCH 08/11] Allow a contract derives from eosio::contract privately --- tests/toolchain/build-pass/separate_cpp_hpp.hpp | 2 +- tools/include/eosio/codegen.hpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/toolchain/build-pass/separate_cpp_hpp.hpp b/tests/toolchain/build-pass/separate_cpp_hpp.hpp index d1685a2858..2002834021 100644 --- a/tests/toolchain/build-pass/separate_cpp_hpp.hpp +++ b/tests/toolchain/build-pass/separate_cpp_hpp.hpp @@ -1,6 +1,6 @@ #include -class [[eosio::contract]] separate_cpp_hpp : public eosio::contract { +class [[eosio::contract]] separate_cpp_hpp : eosio::contract { public: using contract::contract; diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index 123ea3c631..1deae76eff 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -218,7 +218,8 @@ namespace eosio { namespace cdt { // it may not have `set_exec_type()`. We need to make sure the class derives // from `eosio::contract` before calling set_exec_type(). if (base_is_eosio_contract_class(decl)) { - ss << "obj.set_exec_type(eosio::contract::exec_type_t::action);\n"; + // static_cast is for cases when a contract derives from `eosio::contract` privately + ss << "static_castobj.set_exec_type(eosio::contract::exec_type_t::action);\n"; } const auto& call_action = [&]() { @@ -302,7 +303,8 @@ namespace eosio { namespace cdt { // it may not have `set_exec_type()`. We need to make sure the class derives // from `eosio::contract` before calling set_exec_type(). if (base_is_eosio_contract_class(decl)) { - ss << "obj.set_exec_type(eosio::contract::exec_type_t::call);\n"; + // static_cast is for cases when a contract derives from `eosio::contract` privately + ss << "static_castobj.set_exec_type(eosio::contract::exec_type_t::call);\n"; } const auto& call_function = [&]() { From 425fc6c3c237d7a7b9af0cf62b9319af31c10009 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 22 Jul 2025 07:58:24 -0400 Subject: [PATCH 09/11] Add a missing () --- tools/include/eosio/codegen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index 1deae76eff..8d097beb69 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -219,7 +219,7 @@ namespace eosio { namespace cdt { // from `eosio::contract` before calling set_exec_type(). if (base_is_eosio_contract_class(decl)) { // static_cast is for cases when a contract derives from `eosio::contract` privately - ss << "static_castobj.set_exec_type(eosio::contract::exec_type_t::action);\n"; + ss << "static_cast(obj).set_exec_type(eosio::contract::exec_type_t::action);\n"; } const auto& call_action = [&]() { @@ -304,7 +304,7 @@ namespace eosio { namespace cdt { // from `eosio::contract` before calling set_exec_type(). if (base_is_eosio_contract_class(decl)) { // static_cast is for cases when a contract derives from `eosio::contract` privately - ss << "static_castobj.set_exec_type(eosio::contract::exec_type_t::call);\n"; + ss << "static_cast(obj).set_exec_type(eosio::contract::exec_type_t::call);\n"; } const auto& call_function = [&]() { From d607a92712d85365e34767e9d974a5c4e4bb8d3e Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 22 Jul 2025 08:12:13 -0400 Subject: [PATCH 10/11] Revert back the change for allowing private deriving from eosio::contract --- tests/toolchain/build-pass/separate_cpp_hpp.hpp | 2 +- tools/include/eosio/codegen.hpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/toolchain/build-pass/separate_cpp_hpp.hpp b/tests/toolchain/build-pass/separate_cpp_hpp.hpp index 2002834021..d1685a2858 100644 --- a/tests/toolchain/build-pass/separate_cpp_hpp.hpp +++ b/tests/toolchain/build-pass/separate_cpp_hpp.hpp @@ -1,6 +1,6 @@ #include -class [[eosio::contract]] separate_cpp_hpp : eosio::contract { +class [[eosio::contract]] separate_cpp_hpp : public eosio::contract { public: using contract::contract; diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index 8d097beb69..123ea3c631 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -218,8 +218,7 @@ namespace eosio { namespace cdt { // it may not have `set_exec_type()`. We need to make sure the class derives // from `eosio::contract` before calling set_exec_type(). if (base_is_eosio_contract_class(decl)) { - // static_cast is for cases when a contract derives from `eosio::contract` privately - ss << "static_cast(obj).set_exec_type(eosio::contract::exec_type_t::action);\n"; + ss << "obj.set_exec_type(eosio::contract::exec_type_t::action);\n"; } const auto& call_action = [&]() { @@ -303,8 +302,7 @@ namespace eosio { namespace cdt { // it may not have `set_exec_type()`. We need to make sure the class derives // from `eosio::contract` before calling set_exec_type(). if (base_is_eosio_contract_class(decl)) { - // static_cast is for cases when a contract derives from `eosio::contract` privately - ss << "static_cast(obj).set_exec_type(eosio::contract::exec_type_t::call);\n"; + ss << "obj.set_exec_type(eosio::contract::exec_type_t::call);\n"; } const auto& call_function = [&]() { From a762ebdbab74a7c95222d6b5133aae01ee335423 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 23 Jul 2025 15:26:40 -0400 Subject: [PATCH 11/11] Resolve merging conflicts --- libraries/eosiolib/contracts/eosio/action.hpp | 86 ------------------- libraries/eosiolib/contracts/eosio/detail.hpp | 5 ++ 2 files changed, 5 insertions(+), 86 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/action.hpp b/libraries/eosiolib/contracts/eosio/action.hpp index 5c9713fb86..331ddb70d0 100644 --- a/libraries/eosiolib/contracts/eosio/action.hpp +++ b/libraries/eosiolib/contracts/eosio/action.hpp @@ -409,92 +409,6 @@ namespace eosio { }; -<<<<<<< HEAD -======= - - - namespace detail { - - /// @cond INTERNAL - - template - struct unwrap { typedef T type; }; - - template - struct unwrap> { typedef T type; }; - - template - auto get_args(R(Act::*p)(Args...)) { - return std::tuple::type>...>{}; - } - - template - auto get_args_nounwrap(R(Act::*p)(Args...)) { - return std::tuple...>{}; - } - - template - using deduced = decltype(get_args(Action)); - - template - using deduced_nounwrap = decltype(get_args_nounwrap(Action)); - - template - struct convert { typedef T type; }; - - template <> - struct convert { typedef std::string type; }; - - template <> - struct convert { typedef std::string type; }; - - template - struct is_same { static constexpr bool value = std::is_convertible::value; }; - - template - struct is_same { static constexpr bool value = std::is_integral::value; }; - - template - struct is_same { static constexpr bool value = std::is_integral::value; }; - - // Full specialization to resolve ambiguity introduced by partial specializations - // of is_same and is_same - template <> - struct is_same { static constexpr bool value = true; }; - - template - struct get_nth_impl { static constexpr auto value = get_nth_impl::value; }; - - template - struct get_nth_impl { static constexpr auto value = Arg; }; - - template - struct get_nth { static constexpr auto value = get_nth_impl::value; }; - - template - struct check_types { - static_assert(detail::is_same::type, typename convert>::type>::type>::value); - using type = check_types; - static constexpr bool value = true; - }; - template - struct check_types { - static_assert(detail::is_same::type, typename convert>::type>::type>::value); - static constexpr bool value = true; - }; - - template - constexpr bool type_check() { - static_assert(sizeof...(Ts) == std::tuple_size>::value); - if constexpr (sizeof...(Ts) != 0) - return check_types::value; - return true; - } - - /// @endcond - } - ->>>>>>> origin/release/4.1 /** * Wrapper for an action object. * diff --git a/libraries/eosiolib/contracts/eosio/detail.hpp b/libraries/eosiolib/contracts/eosio/detail.hpp index 889bf496be..6a88af66b0 100644 --- a/libraries/eosiolib/contracts/eosio/detail.hpp +++ b/libraries/eosiolib/contracts/eosio/detail.hpp @@ -46,6 +46,11 @@ namespace eosio { namespace detail { template struct is_same { static constexpr bool value = std::is_integral::value; }; + // Full specialization to resolve ambiguity introduced by partial specializations + // of is_same and is_same + template <> + struct is_same { static constexpr bool value = true; }; + template struct get_nth_impl { static constexpr auto value = get_nth_impl::value; };