This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Implement stringbuf members of P0408R7 (Efficient Access to basic_stringbuf's Buffer)
ClosedPublic

Authored by pfusik on Jun 24 2023, 11:31 AM.

Diff Detail

Event Timeline

pfusik created this revision.Jun 24 2023, 11:31 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 24 2023, 11:32 AM
pfusik requested review of this revision.Jun 24 2023, 11:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 24 2023, 11:32 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript

Thanks a lot for splitting, that really helped me to finally do a full review of this patch.
It looks mostely good, some minor things.

libcxx/include/sstream
364

http://eel.is/c++draft/stringbuf#members-15 Constraints: is_same_v<SAlloc,Allocator> is false.

423

We still need to look at this issue.

470

Same here.

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.cons/alloc.pass.cpp
14

Here and in the other tests.

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.cons/string-alloc.mode.pass.cpp
35

How about testing the allocator of buf.str()?
Maybe we should do even more testing the expected allocator is used. The test_allocator has ways to log that information.

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.members/str.alloc.pass.cpp
32

This nesting is not needed.

pfusik updated this revision to Diff 534645.Jun 26 2023, 10:44 AM
pfusik marked 2 inline comments as done.

Address review comments.

pfusik added inline comments.Jun 26 2023, 10:46 AM
libcxx/include/sstream
423

I think it is okay to use nullptr instead of __p obtained from the moved string.
But since it is an unrelated fix, I'd prefer to do this in a separate change.

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.cons/string-alloc.mode.pass.cpp
35

How?
stringbuf fixes its allocator at construction time. Here we are testing a constructor overload that doesn't accept an allocator.

Mordante accepted this revision.Jul 1 2023, 4:42 AM

Thanks LGTM! I'll land the patch on your behalf.

libcxx/include/sstream
365

Nit: we only use std:: for function calls to avoid ADL.

Note since the rest of the patch is fine, I'll fix this before landing.

423

+1 for doing it in a separate patch.

libcxx/test/std/input.output/string.streams/stringbuf/stringbuf.cons/string-alloc.mode.pass.cpp
35

Good point.

This revision is now accepted and ready to land.Jul 1 2023, 4:42 AM
hans added a subscriber: hans.Jul 11 2023, 2:03 AM
hans added inline comments.
libcxx/include/sstream
337

This is causing link errors for us on Windows. (https://crbug.com/1463881)

The problem is that sstream has an explicit instantiation declaration of basic_stringbuf<char> in the sstream header, but when compiling the instantiation in ios.instantiations.cpp, _LIBCPP_BUILDING_LIBRARY is defined and so this string_type str() const & member function doesn't get defined.

(Apologies for the late report; we were blocked on https://reviews.llvm.org/D151953#4472195 until yesterday.)

pfusik added inline comments.Jul 11 2023, 7:14 AM
libcxx/include/sstream
337

str() const & is _LIBCPP_HIDE_FROM_ABI so I think it should NOT be linked.
Why is it __declspec(dllimport) ?

hans added inline comments.Jul 11 2023, 7:34 AM
libcxx/include/sstream
337

The explicit instantiation decl uses _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS which is dllimport: https://github.com/llvm/llvm-project/blob/main/libcxx/include/__config#L564

I think the idea is that _LIBCPP_HIDE_FROM_ABI should exclude the method from the explicit instantiation but that attribute doesn't seem to be really working with dllimport: https://godbolt.org/z/qc3zfvdaa

pfusik added inline comments.Jul 11 2023, 11:07 AM
libcxx/include/sstream
337

Is this issue specific to the str() const & overload?
How do the other _LIBCPP_HIDE_FROM_ABI members work? Are they dllimport too?

hans added a subscriber: ldionne.Jul 12 2023, 6:23 AM
hans added inline comments.
libcxx/include/sstream
337

Yes, we're only seeing this issue for str() const & (I suppose the const && overload has the same problem, but we're not calling it.)

I believe the other members are also dllimport, so in effect the _LIBCPP_HIDE_FROM_ABI isn't working, but it still builds because the members (at least the ones that get called in our builds) do get defined in the dll.

What makes these specific methods problematic is that they're excluded when _LIBCPP_BUILDING_LIBRARY is set. I suppose that's technically an ODR violation, but I can see why it's needed for compatibility.

I suppose we can try to make exclude_from_explicit_instantiation work better with dllimport explicit instantiations, but that means the code would only work with versions of Clang which has that fix.

We could also stop using exclude_from_explicit_instantiation on Windows and go back to _LIBCPP_ALWAYS_INLINE. I guess that was more brittle which is why the attribute was added in the first place though.

Maybe @ldionne has ideas here?

ldionne added inline comments.Jul 12 2023, 8:20 AM
libcxx/include/sstream
337

This seems like https://github.com/llvm/llvm-project/issues/40363. I never had time to look into it, and until now it seemed like it wasn't hard-blocking anyone.

The medium term fix is to fix https://github.com/llvm/llvm-project/issues/40363 and be done with it.
The short term fix could be this:

// TODO(LLVM 19): Remove this once we drop support for Clang 16, which had this bug: https://github.com/llvm/llvm-project/issues/40363
#ifdef _WIN32
_LIBCPP_ALWAYS_INLINE string_type str() const & { return str(__str_.get_allocator()); }
#else
_LIBCPP_HIDE_FROM_ABI string_type str() const & { return str(__str_.get_allocator()); }
#endif

WDYT?

Would someone with Windows access be willing to take on the fix for Clang? I can review it, I'm just really under water until the release. I don't think it's too hard to fix, the attribute was really simple to implement. It would be nice to fix this for LLVM 17, then we can remove the workaround fairly soon.

pfusik added inline comments.Jul 12 2023, 8:33 AM
libcxx/include/sstream
337

I'm fine with both the short and medium term fixes and can do both.

hans added inline comments.Jul 12 2023, 9:42 AM
libcxx/include/sstream
337

Both of these sound good to me too. I just confirmed the short-term one fixes our build, and I'm happy to help with the medium-term one too. (Thanks for finding the bug Louis, I had completely forgotten that we already had it on file.)

ldionne added inline comments.Jul 19 2023, 4:03 PM
libcxx/include/sstream
337

Linking this thread to D155713.

thakis added a subscriber: thakis.Aug 9 2023, 11:27 AM
thakis added inline comments.
libcxx/include/sstream
337

Mentioning this here since this is where the discussion is: We're also seeing "missing symbol" errors for basic_ostringstream::str() (D155276) and basic_stringstream::str() (D155359) when building libc++ as a dll, and using it from client code built as c++17. (_Not_ for the const & overload as above, just for str(void) const.)

(basic_istringstream was D154454 and it probably has similar issues, but we apparently don't have callers to it.)

We only see this for the str() method, but we probably just don't call the str(string) method.

I'm guessing this has a similar cause to what's discussed above. Using the ALWAYS_INLINE hack that was added in D155185 here as well, they go away: https://bugs.chromium.org/p/chromium/issues/detail?id=1463881#c11 For a more complete workaround, I'm guessing we'd have to slap on that attribute to the other functions touched in the revisions linked to above.)

@pfusik Could you extend the workaround to cover those three classes too?

pfusik marked an inline comment as done.Aug 10 2023, 4:54 AM
pfusik added inline comments.
libcxx/include/sstream
337

https://reviews.llvm.org/D157602

My solution retains str() const in the DLL for compatibility with libc++ 16. Could you please verify if that works for you?

thakis added inline comments.Aug 10 2023, 6:47 AM
libcxx/include/sstream
337

Yes, it helps. Thanks!