1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // <ostream>
10 
11 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
12 
13 // This test fails in Windows DLL configurations, due to
14 // __exclude_from_explicit_instantiation__ not behaving as it should in
15 // combination with dllimport (https://llvm.org/PR41018), in combination
16 // with running tests in c++23 mode while building the library in c++20 mode.
17 //
18 // If the library was built in c++23 mode, this test would succeed.
19 //
20 // Older CMake passed -std:c++latest to set C++20 mode on clang-cl, which
21 // hid this issue. With newer CMake versions, it passes -std:c++20 which
22 // makes this fail.
23 //
24 // Marking as UNSUPPORTED instead of XFAIL to avoid spurious failures/successes
25 // depending on the version of CMake used.
26 // TODO: Remove this when the library is built in c++23 mode.
27 //
28 // UNSUPPORTED: windows-dll
29 
30 // template <class charT, class traits = char_traits<charT> >
31 //   class basic_ostream;
32 
33 // basic_ostream& operator<<(const volatile void* val);
34 
35 #include <ostream>
36 #include <cassert>
37 
38 template <class CharT>
39 class testbuf : public std::basic_streambuf<CharT> {
40   typedef std::basic_streambuf<CharT> base;
41   std::basic_string<CharT> str_;
42 
43 public:
testbuf()44   testbuf() {}
45 
str() const46   std::basic_string<CharT> str() const { return std::basic_string<CharT>(base::pbase(), base::pptr()); }
47 
48 protected:
overflow(typename base::int_type ch=base::traits_type::eof ())49   virtual typename base::int_type overflow(typename base::int_type ch = base::traits_type::eof()) {
50     if (ch != base::traits_type::eof()) {
51       int n = static_cast<int>(str_.size());
52       str_.push_back(static_cast<CharT>(ch));
53       str_.resize(str_.capacity());
54       base::setp(const_cast<CharT*>(str_.data()), const_cast<CharT*>(str_.data() + str_.size()));
55       base::pbump(n + 1);
56     }
57     return ch;
58   }
59 };
60 
main(int,char **)61 int main(int, char**) {
62   testbuf<char> sb1;
63   std::ostream os1(&sb1);
64   int n1;
65   os1 << &n1;
66   assert(os1.good());
67   std::string s1 = sb1.str();
68 
69   testbuf<char> sb2;
70   std::ostream os2(&sb2);
71   os2 << static_cast<volatile void*>(&n1);
72   assert(os2.good());
73   std::string s2 = sb2.str();
74 
75   testbuf<char> sb3;
76   std::ostream os3(&sb3);
77   volatile int n3;
78   os3 << &n3;
79   assert(os3.good());
80   std::string s3 = sb3.str();
81 
82   // %p is implementation defined. Instead of validating the
83   // output, at least ensure that it does not generate an empty
84   // string. Also make sure that given two distinct addresses, the
85   // output of %p is different.
86   assert(!s1.empty());
87   assert(!s2.empty());
88   assert(s1 == s2);
89 
90   assert(!s3.empty());
91   assert(s2 != s3);
92 
93   return 0;
94 }
95