diff --git a/xml/issue4264.xml b/xml/issue4264.xml index d0d7f90fbb..a536a21285 100644 --- a/xml/issue4264.xml +++ b/xml/issue4264.xml @@ -14,10 +14,10 @@ Currently the wording in allows implementation to avoid double indirection when constructing owning functions wrappers from another one:

-

+

-2- Let t be an object of a type that is a specialization of function, copyable_function, or move_only_function, such that the target object -x of t has a type that is a specialization of function, +x of t has a type that is a specialization of function, copyable_function, or move_only_function. Each argument of the invocation of x evaluated as part of the invocation of t may alias an argument in the same position in the invocation of t that has the same type, @@ -38,6 +38,131 @@ an implementation to perform such an optimization. As a consequence, it is accep to specify the allowance for all combinations of polymorphic wrappers, even for creating an owning wrapper from a non-owning one, where implementing such an optimization may not be possible.

+ + +

+This wording is relative to . +

+
    + +
  1. Modify as indicated:

    + +
    +

    +-2- Let t be an object of a type that is a specialization of function, +copyable_function, or move_only_function, or function_ref, +such that the target object x of t has a type that is a specialization of function, +copyable_function, ormove_only_function, or function_ref. +Each argument of the invocation of x evaluated as part of the invocation of t +may alias an argument in the same position in the invocation of t that has the same type, +even if the corresponding parameter is not of reference type. +

    +
    + +
  2. +
+ +
+ +2024-05-21; Tomasz's comment and upates proposed resolution + +

+After implementing double indirection avoidance in the libstdc++, I have realized +that above wording change is insufficient to cover all user observable effects of +the change. Revelant quote from the +Avoid double indirection in function_ref from libstdc++ mailing lists: +

+ +
+

+To avoidance of double indirection requires that constructed function_ref, +refers directly to the target function of the source, instead of source, +and this is visible after the assigment: +

+ +
+void foo() noexcept;
+void bar() noexcept;
+
+std::function_ref<void() noexcept> sr(&foo);
+std::function_ref<void()> dr(sr);
+dr(); // calls `foo` regardless of implementation
+
+sr = &bar;
+sr(); // calls `bar`
+dr(); // still calls `foo` if we avoid indirection,
+      // calls `bar` if we do not
+
+ +

+Similary for move_only_function/copyable_function source: +

+ +
+std::move_only_function<void()> sm;
+std::function_ref<void()> dm(sm);
+
+dm(); // UB because `sm` is empty
+
+sm = &foo;
+
+dm(); // remains UB if we avoid indirection,
+      // calls `bar` if we do not.
+
+ +

+While we may want to allow skipping indirection for function_ref, +as this produces same behavior as in case for copy constructor (matching +signatures): +

+ +
+void foo() noexcept;
+void bar() noexcept;
+
+std::function_ref<void() noexcept> sr(&foo);
+std::function_ref<void() noexcept> dr(sr); // copy-cosntructor
+dr(); // calls `foo` regardless of implementation
+
+sr = &bar;
+sr(); // calls `bar`
+dr(); // still calls `foo` if we avoid indirection
+
+ + +

+I do not think this is acceptable for move_only_function. +… +

+ +

+Note that for the same reason, implementations are not free to avoid +dangling when constructing function_ref from reference_wrapper: +

+ +
+auto srw = std::ref(&foo);
+std::function_ref<void()> drw(srw);
+drw(); // calls `foo`
+
+srw = std::ref(&bar);
+drw(); // calls `foo` if we unwrap referenc wrapper,
+       // calls `bar` otherwise.
+
+ +

+Note that this is limited to function_ref due reference nature of this +wrapper. +

+ +
+ +

+The updated resolution allows indirection but making it unspecified if +function_ref constructed from other function_ref specialization, +will refer to source object or its target. +

+ @@ -49,10 +174,10 @@ This wording is relative to .
  • Modify as indicated:

    -

    +

    -2- Let t be an object of a type that is a specialization of function, copyable_function, or move_only_function, or function_ref, -such that the target object x of t has a type that is a specialization of function, +such that the target object x of t has a type that is a specialization of function, copyable_function, ormove_only_function, or function_ref. Each argument of the invocation of x evaluated as part of the invocation of t may alias an argument in the same position in the invocation of t that has the same type, @@ -60,9 +185,45 @@ even if the corresponding parameter is not of reference type.

    +
  • + +
  • Modify as indicated:

    + +
    +
    +template<class F> constexpr function_ref(F&&) noexcept;
    +
    +
    +[…] +

    -7- Effects: +Initializes bound-entity with addressof(f) +and thunk-ptr with the address of a function thunk such that +thunk(bound-entity, call-args...) is expression-equivalent +() to +invoke_r<R>(static_cast<cv T&>(f), call-args...). +

    +

    -X- Remarks: +If remove_cveref_t<F> is specialization of function_ref implementation +may initialize bound-entity with bound-entity of f. +[Example::

    +
    +void f1() noexcept;
    +void f2() noexcept;
    +
    +function_ref<void() noexcept> r1(&r1);
    +function_ref<void()> r2(r1);
    +r1 = &f2;
    +f2(); // it is unspecified if `f1` or `f2` is invoked
    +
    +

    end example]

    +
    +
    +
    +
  • +
    - \ No newline at end of file +