diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -27,7 +27,7 @@ "`P0798R8 `__","LWG","Monadic operations for ``std::optional``","October 2021","","" "`P0849R8 `__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","","" "`P1072R10 `__","LWG","``basic_string::resize_and_overwrite``","October 2021","","" -"`P1147R1 `__","LWG","Printing ``volatile`` Pointers","October 2021","","" +"`P1147R1 `__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0" "`P1272R4 `__","LWG","Byteswapping for fun&&nuf","October 2021","","" "`P1675R2 `__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","","" "`P2077R3 `__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","","" diff --git a/libcxx/include/ostream b/libcxx/include/ostream --- a/libcxx/include/ostream +++ b/libcxx/include/ostream @@ -55,6 +55,7 @@ basic_ostream& operator<<(double f); basic_ostream& operator<<(long double f); basic_ostream& operator<<(const void* p); + basic_ostream& operator<<(const volatile void* val); basic_ostream& operator<<(basic_streambuf* sb); basic_ostream& operator<<(nullptr_t); @@ -210,6 +211,13 @@ basic_ostream& operator<<(double __f); basic_ostream& operator<<(long double __f); basic_ostream& operator<<(const void* __p); + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI basic_ostream& operator<<(const volatile void* __val) { + return operator<<(const_cast(__val)); + } +#endif + basic_ostream& operator<<(basic_streambuf* __sb); _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++17, c++20 + +// template > +// class basic_ostream; + +// operator<<(const volatile void* val); + +#include +#include + +template +class testbuf : public std::basic_streambuf { + typedef std::basic_streambuf base; + std::basic_string str_; + +public: + testbuf() {} + + std::basic_string str() const { return std::basic_string(base::pbase(), base::pptr()); } + +protected: + virtual typename base::int_type overflow(typename base::int_type ch = base::traits_type::eof()) { + if (ch != base::traits_type::eof()) { + int n = static_cast(str_.size()); + str_.push_back(static_cast(ch)); + str_.resize(str_.capacity()); + base::setp(const_cast(str_.data()), const_cast(str_.data() + str_.size())); + base::pbump(n + 1); + } + return ch; + } +}; + +int main(int, char**) { + + testbuf sb1; + std::ostream os1(&sb1); + int n1; + os1 << &n1; + assert(os1.good()); + std::string s1(sb1.str()); + + testbuf sb2; + std::ostream os2(&sb2); + os2 << static_cast(&n1); + assert(os2.good()); + std::string s2(sb2.str()); + + testbuf sb3; + std::ostream os3(&sb3); + volatile int n3; + os3 << &n3; + assert(os3.good()); + std::string s3(sb3.str()); + + // %p is implementation defined. Instead of validating the + // output, at least ensure that it does not generate an empty + // string. Also make sure that given two distinct addresses, the + // output of %p is different. + assert(!s1.empty()); + assert(!s2.empty()); + assert(s1 == s2); + + assert(!s3.empty()); + assert(s2 != s3); + + return 0; +}