55import pytest
66
77import env
8- from pybind11_tests import ConstructorStats
8+ from pybind11_tests import ConstructorStats , defined___cpp_noexcept_function_type
99from pybind11_tests import methods_and_attributes as m
1010
1111NO_GETTER_MSG = (
@@ -555,8 +555,6 @@ def test_rvalue_ref_qualified_methods():
555555 Covers:
556556 - Return (Class::*)(Args...) && (take)
557557 - Return (Class::*)(Args...) const && (peek)
558- - Return (Class::*)(Args...) && noexcept (take_noexcept, C++17 only)
559- - Return (Class::*)(Args...) const && noexcept (peek_noexcept, C++17 only)
560558 """
561559 obj = m .RValueRefDerived ()
562560 # && moves m_payload: first call gets the value, second gets empty string
@@ -565,14 +563,24 @@ def test_rvalue_ref_qualified_methods():
565563 # const && doesn't move: peek() is stable across calls
566564 assert obj .peek () == 77
567565 assert obj .peek () == 77
568- # noexcept variants are bound only under C++17; skip gracefully if absent
569- if hasattr (obj , "take_noexcept" ):
570- obj2 = m .RValueRefDerived ()
571- assert obj2 .take_noexcept () == "rref_payload"
572- assert obj2 .take_noexcept () == ""
573- if hasattr (obj , "peek_noexcept" ):
574- assert obj .peek_noexcept () == 77
575- assert obj .peek_noexcept () == 77
566+
567+
568+ @pytest .mark .skipif (
569+ not defined___cpp_noexcept_function_type ,
570+ reason = "Requires __cpp_noexcept_function_type" ,
571+ )
572+ def test_noexcept_rvalue_ref_qualified_methods ():
573+ """Test noexcept rvalue-ref-qualified methods from an unregistered base.
574+
575+ Covers:
576+ - Return (Class::*)(Args...) && noexcept (take_noexcept)
577+ - Return (Class::*)(Args...) const && noexcept (peek_noexcept)
578+ """
579+ obj = m .RValueRefDerived ()
580+ assert obj .take_noexcept () == "rref_payload"
581+ assert obj .take_noexcept () == ""
582+ assert obj .peek_noexcept () == 77
583+ assert obj .peek_noexcept () == 77
576584
577585
578586def test_noexcept_overload_cast ():
@@ -612,14 +620,25 @@ def test_ref_qualified_overload_cast():
612620 assert obj .method_rref (1.0 ) == "(float) &&"
613621 assert obj .method_const_rref (1.0 ) == "(float) const &&"
614622
615- if hasattr (obj , "method_lref_noexcept" ):
616- assert obj .method_lref_noexcept (1 ) == "(long) & noexcept"
617- if hasattr (obj , "method_const_lref_noexcept" ):
618- assert obj .method_const_lref_noexcept (1 ) == "(long) const & noexcept"
619- if hasattr (obj , "method_rref_noexcept" ):
620- assert obj .method_rref_noexcept (1.0 ) == "(double) && noexcept"
621- if hasattr (obj , "method_const_rref_noexcept" ):
622- assert obj .method_const_rref_noexcept (1.0 ) == "(double) const && noexcept"
623+
624+ @pytest .mark .skipif (
625+ not defined___cpp_noexcept_function_type ,
626+ reason = "Requires __cpp_noexcept_function_type" ,
627+ )
628+ def test_noexcept_ref_qualified_overload_cast ():
629+ """Test issue #2234 follow-up: overload_cast with noexcept ref-qualified member pointers.
630+
631+ Covers:
632+ - overload_cast_impl::operator()(Return (Class::*)(Args...) & noexcept, false_type)
633+ - overload_cast_impl::operator()(Return (Class::*)(Args...) const & noexcept, true_type)
634+ - overload_cast_impl::operator()(Return (Class::*)(Args...) && noexcept, false_type)
635+ - overload_cast_impl::operator()(Return (Class::*)(Args...) const && noexcept, true_type)
636+ """
637+ obj = m .RefQualifiedOverloaded ()
638+ assert obj .method_lref_noexcept (1 ) == "(long) & noexcept"
639+ assert obj .method_const_lref_noexcept (1 ) == "(long) const & noexcept"
640+ assert obj .method_rref_noexcept (1.0 ) == "(double) && noexcept"
641+ assert obj .method_const_rref_noexcept (1.0 ) == "(double) const && noexcept"
623642
624643
625644def test_ref_qualified ():
0 commit comments