ostream.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef COMMON_OSTREAM_H_
  5. #define COMMON_OSTREAM_H_
  6. #include <ostream>
  7. #include "llvm/Support/raw_os_ostream.h"
  8. #include "llvm/Support/raw_ostream.h"
  9. namespace Carbon {
  10. // Support raw_ostream << for types which implement:
  11. // void Print(llvm::raw_ostream& out) const;
  12. template <typename T,
  13. typename = std::enable_if_t<
  14. std::is_member_function_pointer_v<decltype(&T::Print)>>>
  15. auto operator<<(llvm::raw_ostream& out, const T& obj) -> llvm::raw_ostream& {
  16. obj.Print(out);
  17. return out;
  18. }
  19. // Prevents raw_ostream << for pointers to printable types.
  20. template <typename T,
  21. typename = std::enable_if_t<
  22. std::is_member_function_pointer_v<decltype(&T::Print)>>>
  23. __attribute__((unavailable(
  24. "Received a pointer to a printable type, are you missing a `*`? "
  25. "To print as a pointer, cast to void*."))) auto
  26. operator<<(llvm::raw_ostream& out, const T* /*obj*/) -> llvm::raw_ostream&;
  27. // Support std::ostream << for types which implement:
  28. // void Print(llvm::raw_ostream& out) const;
  29. template <typename T,
  30. typename = std::enable_if_t<
  31. std::is_member_function_pointer_v<decltype(&T::Print)>>>
  32. auto operator<<(std::ostream& out, const T& obj) -> std::ostream& {
  33. llvm::raw_os_ostream raw_os(out);
  34. obj.Print(raw_os);
  35. return out;
  36. }
  37. // Prevents std::ostream << for pointers to printable types.
  38. template <typename T,
  39. typename = std::enable_if_t<
  40. std::is_member_function_pointer_v<decltype(&T::Print)>>>
  41. __attribute__((unavailable(
  42. "Received a pointer to a printable type, are you missing a `*`? "
  43. "To print as a pointer, cast to void*."))) auto
  44. operator<<(std::ostream& out, const T* /*obj*/) -> std::ostream&;
  45. // Allow GoogleTest and GoogleMock to print even pointers by dereferencing them.
  46. // This is important to allow automatic printing of arguments of mocked APIs.
  47. template <typename T,
  48. typename = std::enable_if_t<
  49. std::is_member_function_pointer_v<decltype(&T::Print)>>>
  50. void PrintTo(T* p, std::ostream* out) {
  51. *out << static_cast<const void*>(p);
  52. // Also print the object if non-null.
  53. if (p) {
  54. *out << " pointing to " << *p;
  55. }
  56. }
  57. } // namespace Carbon
  58. namespace llvm {
  59. // Injects an `operator<<` overload into the `llvm` namespace which detects LLVM
  60. // types with `raw_ostream` overloads and uses that to map to a `std::ostream`
  61. // overload. This allows LLVM types to be printed to `std::ostream` via their
  62. // `raw_ostream` operator overloads, which is needed both for logging and
  63. // testing.
  64. //
  65. // To make this overload be unusually low priority, it is designed to take even
  66. // the `std::ostream` parameter as a template, and SFINAE disable itself unless
  67. // that template parameter matches `std::ostream`. This ensures that an
  68. // *explicit* operator will be preferred when provided. Some LLVM types may have
  69. // this, and so we want to prioritize accordingly.
  70. //
  71. // It would be slightly cleaner for LLVM itself to provide this overload in
  72. // `raw_os_ostream.h` so that we wouldn't need to inject into its namespace, but
  73. // supporting `std::ostream` isn't a priority for LLVM so we handle it locally
  74. // instead.
  75. template <typename S, typename T,
  76. typename = std::enable_if_t<std::is_base_of_v<
  77. std::ostream, std::remove_reference_t<std::remove_cv_t<S>>>>,
  78. typename = std::enable_if_t<!std::is_same_v<
  79. std::remove_reference_t<std::remove_cv_t<T>>, raw_ostream>>>
  80. auto operator<<(S& standard_out, const T& value) -> S& {
  81. raw_os_ostream(standard_out) << value;
  82. return standard_out;
  83. }
  84. } // namespace llvm
  85. #endif // COMMON_OSTREAM_H_