summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst')
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst60
1 files changed, 60 insertions, 0 deletions
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst
new file mode 100644
index 00000000000..3b57d50549e
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - bugprone-move-forwarding-reference
+
+bugprone-move-forwarding-reference
+==================================
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+ .. code-block:: c++
+
+ template <typename T>
+ void foo(T&& t) {
+ bar(std::move(t));
+ }
+
+`Forwarding references
+<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf>`_ should
+typically be passed to ``std::forward`` instead of ``std::move``, and this is
+the fix that will be suggested.
+
+(A forwarding reference is an rvalue reference of a type that is a deduced
+function template argument.)
+
+In this example, the suggested fix would be
+
+ .. code-block:: c++
+
+ bar(std::forward<T>(t));
+
+Background
+----------
+
+Code like the example above is sometimes written with the expectation that
+``T&&`` will always end up being an rvalue reference, no matter what type is
+deduced for ``T``, and that it is therefore not possible to pass an lvalue to
+``foo()``. However, this is not true. Consider this example:
+
+ .. code-block:: c++
+
+ std::string s = "Hello, world";
+ foo(s);
+
+This code compiles and, after the call to ``foo()``, ``s`` is left in an
+indeterminate state because it has been moved from. This may be surprising to
+the caller of ``foo()`` because no ``std::move`` was used when calling
+``foo()``.
+
+The reason for this behavior lies in the special rule for template argument
+deduction on function templates like ``foo()`` -- i.e. on function templates
+that take an rvalue reference argument of a type that is a deduced function
+template argument. (See section [temp.deduct.call]/3 in the C++11 standard.)
+
+If ``foo()`` is called on an lvalue (as in the example above), then ``T`` is
+deduced to be an lvalue reference. In the example, ``T`` is deduced to be
+``std::string &``. The type of the argument ``t`` therefore becomes
+``std::string& &&``; by the reference collapsing rules, this collapses to
+``std::string&``.
+
+This means that the ``foo(s)`` call passes ``s`` as an lvalue reference, and
+``foo()`` ends up moving ``s`` and thereby placing it into an indeterminate
+state.
OpenPOWER on IntegriCloud