LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 48238 - standard library APIs missing noalias on rvalue references
Summary: standard library APIs missing noalias on rvalue references
Status: NEW
Alias: None
Product: clang
Classification: Unclassified
Component: C++ (show other bugs)
Version: trunk
Hardware: PC Linux
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-11-20 02:31 PST by Gonzalo BG
Modified: 2020-11-24 01:20 PST (History)
9 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Gonzalo BG 2020-11-20 02:31:16 PST
According to the wording and notes in [res.on.arguments]/1.3, standard library APIs taking rvalue references arguments can assume that these do not alias. 

When looking at: https://godbolt.org/z/G8ejKb


#include <utility>
int fails(int* p) {
    int&& i = std::move(std::move(*p));
    return i;
}
int works(int * __restrict p) {
    return *p;
}

the last call to `std::move` in "fails" takes an rvalue reference, and its argument should be `noalias`, which LLVM attributor pass should be able to propagate up to `p`.

However, the generated IR is missing no-alias.

I don't think the standard guarantees that rvalue references are always no alias, but the standard library does guarantee that for all its APIs. 

The simplest solution I can imagine would be to add a [[__std_lib_api__]] builtin attribute that adds `noalias` to all rvalue reference arguments of a function. We'd need to implement the argument, and add it to libc++. 

Richard, Eric, thoughts? 

To me this wording looks extremely powerful, but from https://cplusplus.github.io/LWG/issue1204 I don't know if this is intended or not.
Comment 1 Stefan Stipanovic 2020-11-20 05:25:20 PST
Not that it changes the result, but the godbolt example doesn't actually run the attributor since it is not turned on by default yet.

This does: https://godbolt.org/z/TxxvKx
Comment 2 Gonzalo BG 2020-11-24 01:20:54 PST
It was confirmed in the LWG mailing list that for a standard library API `foo`

    void foo(int&& a, int&& b) { }

the behavior of:

    int a = 42;
    foo(move(a), move(a));

is undefined because the rvalue references passed to "foo" alias and that's not allowed according to [res.on.arguments]/1.3.

---

From a libc++ point-of-view, this probably also means that the standard library needs to be careful of not accessing any static or global from a function that could accept that value as an argument, e.g.,

   int b = 42;
   void foo(int&& a) {
      b += a; // UB if "a" aliases "b"
   }
   foo(move(b)); // UB

and standard library users need to be careful as well:
   
   struct F {
     int* p;
     void operator()(int b) {}
   };
   int test() {
     int a = 42;
     std::async(
       F{&a},
       std::move(a) // "a" aliases "F.p"
     );   
   }