From 7be8a41adf368b48350e5906568adf34579d4718 Mon Sep 17 00:00:00 2001 From: Julien Nitard Date: Wed, 30 May 2018 21:32:59 -0500 Subject: [PATCH] Fix ambiguity in stringification Happening when using clang and templated operators, clang cannot decide between the operator provided by ReusableStringStream and the one provided by the value value as both are templates. This is easily solved by calling the operator<< through the member syntax. Fixes #1285 --- include/internal/catch_tostring.h | 4 +++- .../SelfTest/Baselines/compact.sw.approved.txt | 3 +++ .../Baselines/console.std.approved.txt | 4 ++-- .../SelfTest/Baselines/console.sw.approved.txt | 18 ++++++++++++++++-- .../SelfTest/Baselines/junit.sw.approved.txt | 3 ++- .../SelfTest/Baselines/xml.sw.approved.txt | 17 +++++++++++++++-- .../UsageTests/ToStringWhich.tests.cpp | 13 +++++++++++++ 7 files changed, 54 insertions(+), 8 deletions(-) diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h index 81c87231..2aa06f44 100644 --- a/include/internal/catch_tostring.h +++ b/include/internal/catch_tostring.h @@ -105,7 +105,9 @@ namespace Catch { typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type convert(const Fake& value) { ReusableStringStream rss; - rss << value; + // NB: call using the function-like syntax to avoid ambiguity with + // user-defined templated operator<< under clang. + rss.operator<<(value); return rss.str(); } diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt index 7e844449..24d9b1b7 100644 --- a/projects/SelfTest/Baselines/compact.sw.approved.txt +++ b/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -1065,6 +1065,9 @@ ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify(item) ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )" == "operator<<( has_operator )" +ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" for: "operator<<( has_template_operator )" +== +"operator<<( has_template_operator )" ToStringWhich.tests.cpp:: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker }" for: "{ StringMaker }" == "{ StringMaker }" diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index ff31a88a..1992fb9f 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -1084,6 +1084,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 207 | 154 passed | 49 failed | 4 failed as expected -assertions: 1064 | 936 passed | 107 failed | 21 failed as expected +test cases: 208 | 155 passed | 49 failed | 4 failed as expected +assertions: 1065 | 937 passed | 107 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index a32ef10e..047c7163 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -8407,6 +8407,20 @@ with expansion: == "operator<<( has_operator )" +------------------------------------------------------------------------------- +stringify( has_template_operator ) +------------------------------------------------------------------------------- +ToStringWhich.tests.cpp: +............................................................................... + +ToStringWhich.tests.cpp:: +PASSED: + REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" ) +with expansion: + "operator<<( has_template_operator )" + == + "operator<<( has_template_operator )" + ------------------------------------------------------------------------------- stringify( vectors ) ------------------------------------------------------------------------------- @@ -8978,6 +8992,6 @@ Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 207 | 141 passed | 62 failed | 4 failed as expected -assertions: 1078 | 936 passed | 121 failed | 21 failed as expected +test cases: 208 | 142 passed | 62 failed | 4 failed as expected +assertions: 1079 | 937 passed | 121 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index ffc85e6b..62ca9094 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -838,6 +838,7 @@ Tricky.tests.cpp: + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index af7f468e..5452f2fa 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -9366,6 +9366,19 @@ loose text artifact + + + + ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" + + + "operator<<( has_template_operator )" +== +"operator<<( has_template_operator )" + + + + @@ -9923,7 +9936,7 @@ loose text artifact - + - + diff --git a/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp b/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp index 7be99dcd..26afa3b1 100644 --- a/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp +++ b/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp @@ -20,6 +20,7 @@ struct has_operator { }; struct has_maker {}; struct has_maker_and_operator {}; struct has_neither {}; +struct has_template_operator {}; std::ostream& operator<<(std::ostream& os, const has_operator&) { os << "operator<<( has_operator )"; @@ -31,6 +32,12 @@ std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) { return os; } +template +StreamT& operator<<(StreamT& os, const has_template_operator&) { + os << "operator<<( has_template_operator )"; + return os; +} + namespace Catch { template<> struct StringMaker { @@ -69,6 +76,12 @@ TEST_CASE("stringify( has_neither )", "[toString]") { REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" ); } +// Call the templated operator +TEST_CASE( "stringify( has_template_operator )", "[toString]" ) { + has_template_operator item; + REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" ); +} + // Vectors...