diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index 53d29f1016..1d8182189d 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -44,6 +44,7 @@ #include "src/tint/type/texture_dimension.h" #include "src/tint/utils/reverse.h" #include "src/tint/utils/string.h" +#include "src/tint/utils/string_stream.h" namespace tint::reader::wgsl { namespace { @@ -911,7 +912,7 @@ Expect ParserImpl::expect_enum(std::string_view name, } /// Create a sensible error message - std::ostringstream err; + utils::StringStream err; err << "expected " << name; if (!use.empty()) { diff --git a/src/tint/resolver/alias_analysis_test.cc b/src/tint/resolver/alias_analysis_test.cc index fa70a7fcb0..895ed883da 100644 --- a/src/tint/resolver/alias_analysis_test.cc +++ b/src/tint/resolver/alias_analysis_test.cc @@ -14,6 +14,7 @@ #include "src/tint/resolver/resolver.h" #include "src/tint/resolver/resolver_test_helper.h" +#include "src/tint/utils/string_stream.h" #include "gmock/gmock.h" @@ -196,7 +197,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverAliasAnalysisTest, TwoPointerConfig{builtin::AddressSpace::kPrivate, false}, TwoPointerConfig{builtin::AddressSpace::kPrivate, true}), [](const ::testing::TestParamInfo& p) { - std::stringstream ss; + utils::StringStream ss; ss << (p.param.aliased ? "Aliased" : "Unaliased") << "_" << p.param.address_space; return ss.str(); diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc index 43e9929ec3..b0a863d904 100644 --- a/src/tint/resolver/attribute_validation_test.cc +++ b/src/tint/resolver/attribute_validation_test.cc @@ -18,6 +18,7 @@ #include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/transform/add_block_attribute.h" #include "src/tint/type/texture_dimension.h" +#include "src/tint/utils/string_stream.h" #include "gmock/gmock.h" @@ -1164,7 +1165,7 @@ TEST_P(ArrayStrideTest, All) { auto& params = GetParam(); ast::Type el_ty = params.create_el_type(*this); - std::stringstream ss; + utils::StringStream ss; ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride << ", should_pass: " << params.should_pass; SCOPED_TRACE(ss.str()); diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc index 6a9e5a39a3..0108e895d1 100644 --- a/src/tint/resolver/builtin_test.cc +++ b/src/tint/resolver/builtin_test.cc @@ -38,6 +38,7 @@ #include "src/tint/type/test_helper.h" #include "src/tint/type/texture_dimension.h" #include "src/tint/utils/string.h" +#include "src/tint/utils/string_stream.h" using ::testing::ElementsAre; using ::testing::HasSubstr; @@ -2185,7 +2186,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest, static std::string to_str(const std::string& function, utils::VectorRef params) { - std::stringstream out; + utils::StringStream out; out << function << "("; bool first = true; for (auto* param : params) { diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc index 967335df41..d0747032ab 100644 --- a/src/tint/resolver/builtin_validation_test.cc +++ b/src/tint/resolver/builtin_validation_test.cc @@ -17,6 +17,7 @@ #include "src/tint/ast/builtin_texture_helper_test.h" #include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/sem/value_constructor.h" +#include "src/tint/utils/string_stream.h" using namespace tint::number_suffixes; // NOLINT @@ -335,7 +336,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, Immediate) { EXPECT_TRUE(r()->Resolve()) << r()->error(); } else { EXPECT_FALSE(r()->Resolve()); - std::stringstream err; + utils::StringStream err; if (is_vector) { err << "12:34 error: each component of the " << param.name << " argument must be at least " << param.min << " and at most " << param.max @@ -392,7 +393,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalConst) { EXPECT_TRUE(r()->Resolve()) << r()->error(); } else { EXPECT_FALSE(r()->Resolve()); - std::stringstream err; + utils::StringStream err; if (is_vector) { err << "12:34 error: each component of the " << param.name << " argument must be at least " << param.min << " and at most " << param.max @@ -442,7 +443,7 @@ TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalVar) { }); EXPECT_FALSE(r()->Resolve()); - std::stringstream err; + utils::StringStream err; err << "12:34 error: the " << param.name << " argument must be a const-expression"; EXPECT_EQ(r()->error(), err.str()); } diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc index 63e5abfbff..a985a1dcc6 100644 --- a/src/tint/resolver/builtins_validation_test.cc +++ b/src/tint/resolver/builtins_validation_test.cc @@ -15,6 +15,7 @@ #include "src/tint/ast/call_statement.h" #include "src/tint/builtin/builtin_value.h" #include "src/tint/resolver/resolver_test_helper.h" +#include "src/tint/utils/string_stream.h" using namespace tint::number_suffixes; // NOLINT @@ -145,7 +146,7 @@ TEST_P(ResolverBuiltinsStageTest, All_input) { if (params.is_valid) { EXPECT_TRUE(r()->Resolve()) << r()->error(); } else { - std::stringstream err; + utils::StringStream err; err << "12:34 error: @builtin(" << params.builtin << ")"; err << " cannot be used in input of " << params.stage << " pipeline stage"; EXPECT_FALSE(r()->Resolve()); diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc index d54ad8a501..325ccb0ea9 100644 --- a/src/tint/resolver/const_eval.cc +++ b/src/tint/resolver/const_eval.cc @@ -44,6 +44,7 @@ #include "src/tint/utils/bitcast.h" #include "src/tint/utils/compiler_macros.h" #include "src/tint/utils/map.h" +#include "src/tint/utils/string_stream.h" #include "src/tint/utils/transform.h" using namespace tint::number_suffixes; // NOLINT @@ -184,8 +185,7 @@ auto ZeroTypeDispatch(const type::Type* type, F&& f) { template std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) { - std::stringstream ss; - ss << std::setprecision(20); + utils::StringStream ss; ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '" << FriendlyName() << "'"; return ss.str(); @@ -193,8 +193,7 @@ std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) { template std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) { - std::stringstream ss; - ss << std::setprecision(20); + utils::StringStream ss; ss << "value " << value << " cannot be represented as " << "'" << target_ty << "'"; return ss.str(); @@ -202,8 +201,7 @@ std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) { template std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) { - std::stringstream ss; - ss << std::setprecision(20); + utils::StringStream ss; ss << base << "^" << exp << " cannot be represented as " << "'" << FriendlyName() << "'"; return ss.str(); diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc index e2dec195a1..0ddbeeb99d 100644 --- a/src/tint/resolver/const_eval_binary_op_test.cc +++ b/src/tint/resolver/const_eval_binary_op_test.cc @@ -1077,7 +1077,15 @@ TEST_F(ResolverConstEvalTest, BinaryAbstractAddOverflow_AFloat) { GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Highest()), AFloat::Highest())); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), - "1:1 error: '1.7976931348623157081e+308 + 1.7976931348623157081e+308' cannot be " + "1:1 error: " + "'17976931348623157081452742373170435679807056752584499659891747680315726078002853876" + "058955863276687817154045895351438246423432132688946418276846754670353751698604991057" + "655128207624549009038932894407586850845513394230458323690322294816580855933212334827" + "4797826204144723168738177180919299881250404026184124858368.0 + " + "179769313486231570814527423731704356798070567525844996598917476803157260780028538760" + "589558632766878171540458953514382464234321326889464182768467546703537516986049910576" + "551282076245490090389328944075868508455133942304583236903222948165808559332123348274" + "797826204144723168738177180919299881250404026184124858368.0' cannot be " "represented as 'abstract-float'"); } @@ -1085,7 +1093,16 @@ TEST_F(ResolverConstEvalTest, BinaryAbstractAddUnderflow_AFloat) { GlobalConst("c", Add(Source{{1, 1}}, Expr(AFloat::Lowest()), AFloat::Lowest())); EXPECT_FALSE(r()->Resolve()); EXPECT_EQ(r()->error(), - "1:1 error: '-1.7976931348623157081e+308 + -1.7976931348623157081e+308' cannot be " + "1:1 error: " + "'-" + "179769313486231570814527423731704356798070567525844996598917476803157260780028538760" + "589558632766878171540458953514382464234321326889464182768467546703537516986049910576" + "551282076245490090389328944075868508455133942304583236903222948165808559332123348274" + "797826204144723168738177180919299881250404026184124858368.0 + " + "-17976931348623157081452742373170435679807056752584499659891747680315726078002853876" + "058955863276687817154045895351438246423432132688946418276846754670353751698604991057" + "655128207624549009038932894407586850845513394230458323690322294816580855933212334827" + "4797826204144723168738177180919299881250404026184124858368.0' cannot be " "represented as 'abstract-float'"); } @@ -1584,8 +1601,13 @@ TEST_F(ResolverConstEvalTest, NonShortCircuit_And_Invalid_Materialize) { GlobalConst("result", binary); EXPECT_FALSE(r()->Resolve()); - EXPECT_EQ(r()->error(), - "12:34 error: value 1.7976931348623157081e+308 cannot be represented as 'f32'"); + EXPECT_EQ( + r()->error(), + "12:34 error: value " + "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558" + "632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245" + "490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168" + "738177180919299881250404026184124858368.000000000 cannot be represented as 'f32'"); } TEST_F(ResolverConstEvalTest, ShortCircuit_And_Error_Materialize) { @@ -1630,8 +1652,13 @@ TEST_F(ResolverConstEvalTest, NonShortCircuit_Or_Invalid_Materialize) { GlobalConst("result", binary); EXPECT_FALSE(r()->Resolve()); - EXPECT_EQ(r()->error(), - "12:34 error: value 1.7976931348623157081e+308 cannot be represented as 'f32'"); + EXPECT_EQ( + r()->error(), + "12:34 error: value " + "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558" + "632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245" + "490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168" + "738177180919299881250404026184124858368.000000000 cannot be represented as 'f32'"); } TEST_F(ResolverConstEvalTest, ShortCircuit_Or_Error_Materialize) { diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc index 4e3cb5a72d..6f53af1d7b 100644 --- a/src/tint/resolver/const_eval_builtin_test.cc +++ b/src/tint/resolver/const_eval_builtin_test.cc @@ -2025,9 +2025,11 @@ std::vector Pack2x16floatCases() { C({Vec(f32(10), f32(-10.5))}, Val(u32(0xc940'4900))), E({Vec(f32(0), f32::Highest())}, - "12:34 error: value 3.4028234663852885981e+38 cannot be represented as 'f16'"), + "12:34 error: value 340282346638528859811704183484516925440.000000000 cannot be " + "represented as 'f16'"), E({Vec(f32::Lowest(), f32(0))}, - "12:34 error: value -3.4028234663852885981e+38 cannot be represented as 'f16'"), + "12:34 error: value -340282346638528859811704183484516925440.000000000 cannot be " + "represented as 'f16'"), }; } INSTANTIATE_TEST_SUITE_P( // @@ -2848,15 +2850,16 @@ std::vector QuantizeToF16Cases() { Vec(0x0.034p-14_f, -0x0.034p-14_f, 0x0.068p-14_f, -0x0.068p-14_f)), // Value out of f16 range - E({65504.003_f}, "12:34 error: value 65504.00390625 cannot be represented as 'f16'"), - E({-65504.003_f}, "12:34 error: value -65504.00390625 cannot be represented as 'f16'"), - E({0x1.234p56_f}, "12:34 error: value 81979586966978560 cannot be represented as 'f16'"), + E({65504.003_f}, "12:34 error: value 65504.003906250 cannot be represented as 'f16'"), + E({-65504.003_f}, "12:34 error: value -65504.003906250 cannot be represented as 'f16'"), + E({0x1.234p56_f}, + "12:34 error: value 81979586966978560.000000000 cannot be represented as 'f16'"), E({0x4.321p65_f}, - "12:34 error: value 1.5478871919272394752e+20 cannot be represented as 'f16'"), + "12:34 error: value 154788719192723947520.000000000 cannot be represented as 'f16'"), E({Vec(65504.003_f, 0_f)}, - "12:34 error: value 65504.00390625 cannot be represented as 'f16'"), + "12:34 error: value 65504.003906250 cannot be represented as 'f16'"), E({Vec(0_f, -0x4.321p65_f)}, - "12:34 error: value -1.5478871919272394752e+20 cannot be represented as 'f16'"), + "12:34 error: value -154788719192723947520.000000000 cannot be represented as 'f16'"), }; } INSTANTIATE_TEST_SUITE_P( // diff --git a/src/tint/resolver/const_eval_conversion_test.cc b/src/tint/resolver/const_eval_conversion_test.cc index bcad648f78..b6bcc56e22 100644 --- a/src/tint/resolver/const_eval_conversion_test.cc +++ b/src/tint/resolver/const_eval_conversion_test.cc @@ -431,7 +431,8 @@ TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_f16) { WrapInFunction(expr); EXPECT_FALSE(r()->Resolve()); - EXPECT_EQ(r()->error(), "12:34 error: value 10000000000 cannot be represented as 'f16'"); + EXPECT_EQ(r()->error(), + "12:34 error: value 10000000000.000000000 cannot be represented as 'f16'"); } TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) { diff --git a/src/tint/resolver/const_eval_runtime_semantics_test.cc b/src/tint/resolver/const_eval_runtime_semantics_test.cc index bc7f3c8ac2..347e41df68 100644 --- a/src/tint/resolver/const_eval_runtime_semantics_test.cc +++ b/src/tint/resolver/const_eval_runtime_semantics_test.cc @@ -75,7 +75,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_AFloat_Overflow) { EXPECT_EQ(result.Get()->ValueAs(), 0.f); EXPECT_EQ( error(), - R"(warning: '1.7976931348623157081e+308 + 1.7976931348623157081e+308' cannot be represented as 'abstract-float')"); + R"(warning: '179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 + 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_F32_Overflow) { @@ -86,7 +86,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Add_F32_Overflow) { EXPECT_EQ(result.Get()->ValueAs(), 0.f); EXPECT_EQ( error(), - R"(warning: '3.4028234663852885981e+38 + 3.4028234663852885981e+38' cannot be represented as 'f32')"); + R"(warning: '340282346638528859811704183484516925440.0 + 340282346638528859811704183484516925440.0' cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_AInt_Overflow) { @@ -107,7 +107,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_AFloat_Overflow) { EXPECT_EQ(result.Get()->ValueAs(), 0.f); EXPECT_EQ( error(), - R"(warning: '-1.7976931348623157081e+308 - 1.7976931348623157081e+308' cannot be represented as 'abstract-float')"); + R"(warning: '-179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 - 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_F32_Overflow) { @@ -118,7 +118,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sub_F32_Overflow) { EXPECT_EQ(result.Get()->ValueAs(), 0.f); EXPECT_EQ( error(), - R"(warning: '-3.4028234663852885981e+38 - 3.4028234663852885981e+38' cannot be represented as 'f32')"); + R"(warning: '-340282346638528859811704183484516925440.0 - 340282346638528859811704183484516925440.0' cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_AInt_Overflow) { @@ -139,7 +139,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_AFloat_Overflow) { EXPECT_EQ(result.Get()->ValueAs(), 0.f); EXPECT_EQ( error(), - R"(warning: '1.7976931348623157081e+308 * 1.7976931348623157081e+308' cannot be represented as 'abstract-float')"); + R"(warning: '179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 * 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0' cannot be represented as 'abstract-float')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_F32_Overflow) { @@ -150,7 +150,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mul_F32_Overflow) { EXPECT_EQ(result.Get()->ValueAs(), 0.f); EXPECT_EQ( error(), - R"(warning: '3.4028234663852885981e+38 * 3.4028234663852885981e+38' cannot be represented as 'f32')"); + R"(warning: '340282346638528859811704183484516925440.0 * 340282346638528859811704183484516925440.0' cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_AInt_ZeroDenominator) { @@ -186,7 +186,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_AFloat_ZeroDenominator) { auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 42.f); - EXPECT_EQ(error(), R"(warning: '42 / 0' cannot be represented as 'abstract-float')"); + EXPECT_EQ(error(), R"(warning: '42.0 / 0.0' cannot be represented as 'abstract-float')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_F32_ZeroDenominator) { @@ -195,7 +195,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_F32_ZeroDenominator) { auto result = const_eval.OpDivide(a->Type(), utils::Vector{a, b}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 42.f); - EXPECT_EQ(error(), R"(warning: '42 / 0' cannot be represented as 'f32')"); + EXPECT_EQ(error(), R"(warning: '42.0 / 0.0' cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Div_I32_MostNegativeByMinInt) { @@ -240,7 +240,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_AFloat_ZeroDenominator) { auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0.f); - EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'abstract-float')"); + EXPECT_EQ(error(), R"(warning: '42.0 % 0.0' cannot be represented as 'abstract-float')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_F32_ZeroDenominator) { @@ -249,7 +249,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_F32_ZeroDenominator) { auto result = const_eval.OpModulo(a->Type(), utils::Vector{a, b}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0.f); - EXPECT_EQ(error(), R"(warning: '42 % 0' cannot be represented as 'f32')"); + EXPECT_EQ(error(), R"(warning: '42.0 % 0.0' cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Mod_I32_MostNegativeByMinInt) { @@ -363,7 +363,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp_F32_Overflow) { auto result = const_eval.exp(a->Type(), utils::Vector{a}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0.f); - EXPECT_EQ(error(), R"(warning: e^1000 cannot be represented as 'f32')"); + EXPECT_EQ(error(), R"(warning: e^1000.000000000 cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp2_F32_Overflow) { @@ -371,7 +371,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Exp2_F32_Overflow) { auto result = const_eval.exp2(a->Type(), utils::Vector{a}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0.f); - EXPECT_EQ(error(), R"(warning: 2^1000 cannot be represented as 'f32')"); + EXPECT_EQ(error(), R"(warning: 2^1000.000000000 cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, ExtractBits_I32_TooManyBits) { @@ -476,7 +476,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pack2x16Float_OutOfRange) { auto result = const_eval.pack2x16float(create(), utils::Vector{vec}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0x51430000); - EXPECT_EQ(error(), R"(warning: value 75250 cannot be represented as 'f16')"); + EXPECT_EQ(error(), R"(warning: value 75250.000000000 cannot be represented as 'f16')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pow_F32_Overflow) { @@ -485,7 +485,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Pow_F32_Overflow) { auto result = const_eval.pow(a->Type(), utils::Vector{a, b}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0.f); - EXPECT_EQ(error(), R"(warning: '2 ^ 1000' cannot be represented as 'f32')"); + EXPECT_EQ(error(), R"(warning: '2.0 ^ 1000.0' cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Unpack2x16Float_OutOfRange) { @@ -502,7 +502,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, QuantizeToF16_OutOfRange) { auto result = const_eval.quantizeToF16(create(), utils::Vector{a}, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), 0); - EXPECT_EQ(error(), R"(warning: value 75250 cannot be represented as 'f16')"); + EXPECT_EQ(error(), R"(warning: value 75250.000000000 cannot be represented as 'f16')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Sqrt_F32_OutOfRange) { @@ -534,8 +534,9 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooHigh) { auto result = const_eval.Convert(create(), a, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), f32::kHighestValue); - EXPECT_EQ(error(), - R"(warning: value 1.7976931348623157081e+308 cannot be represented as 'f32')"); + EXPECT_EQ( + error(), + R"(warning: value 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000000 cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooLow) { @@ -543,8 +544,9 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F32_TooLow) { auto result = const_eval.Convert(create(), a, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), f32::kLowestValue); - EXPECT_EQ(error(), - R"(warning: value -1.7976931348623157081e+308 cannot be represented as 'f32')"); + EXPECT_EQ( + error(), + R"(warning: value -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000000 cannot be represented as 'f32')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooHigh) { @@ -552,7 +554,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooHigh) { auto result = const_eval.Convert(create(), a, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), f16::kHighestValue); - EXPECT_EQ(error(), R"(warning: value 1000000 cannot be represented as 'f16')"); + EXPECT_EQ(error(), R"(warning: value 1000000.000000000 cannot be represented as 'f16')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooLow) { @@ -560,7 +562,7 @@ TEST_F(ResolverConstEvalRuntimeSemanticsTest, Convert_F16_TooLow) { auto result = const_eval.Convert(create(), a, {}); ASSERT_TRUE(result); EXPECT_EQ(result.Get()->ValueAs(), f16::kLowestValue); - EXPECT_EQ(error(), R"(warning: value -1000000 cannot be represented as 'f16')"); + EXPECT_EQ(error(), R"(warning: value -1000000.000000000 cannot be represented as 'f16')"); } TEST_F(ResolverConstEvalRuntimeSemanticsTest, Vec_Overflow_SingleComponent) { diff --git a/src/tint/resolver/const_eval_test.h b/src/tint/resolver/const_eval_test.h index 001d3d1186..de25b202f2 100644 --- a/src/tint/resolver/const_eval_test.h +++ b/src/tint/resolver/const_eval_test.h @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/type/test_helper.h" +#include "src/tint/utils/string_stream.h" namespace tint::resolver { @@ -218,8 +219,7 @@ inline void ConcatIntoIf([[maybe_unused]] Vec& v1, [[maybe_unused]] Vecs&&... vs /// Returns the overflow error message for binary ops template inline std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs) { - std::stringstream ss; - ss << std::setprecision(20); + utils::StringStream ss; ss << "'" << lhs.value << " " << op << " " << rhs.value << "' cannot be represented as '" << FriendlyName() << "'"; return ss.str(); @@ -228,8 +228,7 @@ inline std::string OverflowErrorMessage(NumberT lhs, const char* op, NumberT rhs /// Returns the overflow error message for conversions template std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) { - std::stringstream ss; - ss << std::setprecision(20); + utils::StringStream ss; ss << "value " << value << " cannot be represented as " << "'" << target_ty << "'"; return ss.str(); @@ -238,8 +237,7 @@ std::string OverflowErrorMessage(VALUE_TY value, std::string_view target_ty) { /// Returns the overflow error message for exponentiation template std::string OverflowExpErrorMessage(std::string_view base, NumberT exp) { - std::stringstream ss; - ss << std::setprecision(20); + utils::StringStream ss; ss << base << "^" << exp << " cannot be represented as " << "'" << FriendlyName() << "'"; return ss.str(); diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc index 0b8f728934..9b6d471714 100644 --- a/src/tint/resolver/dependency_graph.cc +++ b/src/tint/resolver/dependency_graph.cc @@ -65,6 +65,7 @@ #include "src/tint/utils/defer.h" #include "src/tint/utils/map.h" #include "src/tint/utils/scoped_assignment.h" +#include "src/tint/utils/string_stream.h" #include "src/tint/utils/unique_vector.h" #define TINT_DUMP_DEPENDENCY_GRAPH 0 @@ -711,7 +712,7 @@ struct DependencyAnalysis { /// found in `stack`. /// @param stack is the global dependency stack that contains a loop. void CyclicDependencyFound(const Global* root, utils::VectorRef stack) { - std::stringstream msg; + utils::StringStream msg; msg << "cyclic dependency found: "; constexpr size_t kLoopNotStarted = ~0u; size_t loop_start = kLoopNotStarted; diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc index 27adcad3a5..6654c4304c 100644 --- a/src/tint/resolver/function_validation_test.cc +++ b/src/tint/resolver/function_validation_test.cc @@ -18,6 +18,7 @@ #include "src/tint/builtin/builtin_value.h" #include "src/tint/resolver/resolver.h" #include "src/tint/resolver/resolver_test_helper.h" +#include "src/tint/utils/string_stream.h" #include "gmock/gmock.h" @@ -1054,7 +1055,7 @@ TEST_P(ResolverFunctionParameterValidationTest, AddressSpaceNoExtension) { if (param.expectation == Expectation::kAlwaysPass) { ASSERT_TRUE(r()->Resolve()) << r()->error(); } else { - std::stringstream ss; + utils::StringStream ss; ss << param.address_space; EXPECT_FALSE(r()->Resolve()); if (param.expectation == Expectation::kInvalid) { diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index 623c08bb65..0d2cc10838 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -39,6 +39,7 @@ #include "src/tint/utils/hashmap.h" #include "src/tint/utils/math.h" #include "src/tint/utils/scoped_assignment.h" +#include "src/tint/utils/string_stream.h" namespace tint::resolver { namespace { @@ -1202,12 +1203,12 @@ class Impl : public IntrinsicTable { sem::EvaluationStage earliest_eval_stage) const; // Prints the overload for emitting diagnostics - void PrintOverload(std::ostream& ss, + void PrintOverload(utils::StringStream& ss, const OverloadInfo* overload, const char* intrinsic_name) const; // Prints the list of candidates for emitting diagnostics - void PrintCandidates(std::ostream& ss, + void PrintCandidates(utils::StringStream& ss, utils::VectorRef candidates, const char* intrinsic_name) const; @@ -1232,7 +1233,7 @@ std::string CallSignature(ProgramBuilder& builder, const char* intrinsic_name, utils::VectorRef args, const type::Type* template_arg = nullptr) { - std::stringstream ss; + utils::StringStream ss; ss << intrinsic_name; if (template_arg) { ss << "<" << template_arg->FriendlyName(builder.Symbols()) << ">"; @@ -1271,7 +1272,7 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type, // Generates an error when no overloads match the provided arguments auto on_no_match = [&](utils::VectorRef candidates) { - std::stringstream ss; + utils::StringStream ss; ss << "no matching call to " << CallSignature(builder, intrinsic_name, args) << std::endl; if (!candidates.IsEmpty()) { ss << std::endl @@ -1340,7 +1341,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op, // Generates an error when no overloads match the provided arguments auto on_no_match = [&, name = intrinsic_name](utils::VectorRef candidates) { - std::stringstream ss; + utils::StringStream ss; ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl; if (!candidates.IsEmpty()) { ss << std::endl @@ -1418,7 +1419,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op, // Generates an error when no overloads match the provided arguments auto on_no_match = [&, name = intrinsic_name](utils::VectorRef candidates) { - std::stringstream ss; + utils::StringStream ss; ss << "no matching overload for " << CallSignature(builder, name, args) << std::endl; if (!candidates.IsEmpty()) { ss << std::endl @@ -1453,7 +1454,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type, // Generates an error when no overloads match the provided arguments auto on_no_match = [&](utils::VectorRef candidates) { - std::stringstream ss; + utils::StringStream ss; ss << "no matching constructor for " << CallSignature(builder, name, args, template_arg) << std::endl; Candidates ctor, conv; @@ -1755,7 +1756,7 @@ MatchState Impl::Match(TemplateState& templates, return MatchState(builder, templates, matchers, overload, matcher_indices, earliest_eval_stage); } -void Impl::PrintOverload(std::ostream& ss, +void Impl::PrintOverload(utils::StringStream& ss, const OverloadInfo* overload, const char* intrinsic_name) const { TemplateState templates; @@ -1827,7 +1828,7 @@ void Impl::PrintOverload(std::ostream& ss, } } -void Impl::PrintCandidates(std::ostream& ss, +void Impl::PrintCandidates(utils::StringStream& ss, utils::VectorRef candidates, const char* intrinsic_name) const { for (auto& candidate : candidates) { @@ -1865,7 +1866,7 @@ void Impl::ErrAmbiguousOverload(const char* intrinsic_name, utils::VectorRef args, TemplateState templates, utils::VectorRef candidates) const { - std::stringstream ss; + utils::StringStream ss; ss << "ambiguous overload while attempting to match " << intrinsic_name; for (size_t i = 0; i < std::numeric_limits::max(); i++) { if (auto* ty = templates.Type(i)) { diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl index 1143d98388..9aa0b76d88 100644 --- a/src/tint/resolver/intrinsic_table.inl +++ b/src/tint/resolver/intrinsic_table.inl @@ -71,7 +71,7 @@ const type::Type* Ia::Match(MatchState& state, const type::Type* ty) const { } std::string Ia::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; ss << "abstract-int"; return ss.str(); } @@ -99,7 +99,7 @@ const type::Type* Fa::Match(MatchState& state, const type::Type* ty) const { } std::string Fa::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; ss << "abstract-float"; return ss.str(); } @@ -627,7 +627,7 @@ const type::Type* Vec::Match(MatchState& state, const type::Type* ty) const { std::string Vec::String(MatchState* state) const { const std::string N = state->NumName(); const std::string T = state->TypeName(); - std::stringstream ss; + utils::StringStream ss; ss << "vec" << N << "<" << T << ">"; return ss.str(); } @@ -673,7 +673,7 @@ std::string Mat::String(MatchState* state) const { const std::string N = state->NumName(); const std::string M = state->NumName(); const std::string T = state->TypeName(); - std::stringstream ss; + utils::StringStream ss; ss << "mat" << N << "x" << M << "<" << T << ">"; return ss.str(); } @@ -1431,7 +1431,7 @@ const type::Type* ModfResult::Match(MatchState& state, const type::Type* ty) con std::string ModfResult::String(MatchState* state) const { const std::string T = state->TypeName(); - std::stringstream ss; + utils::StringStream ss; ss << "__modf_result_" << T; return ss.str(); } @@ -1471,7 +1471,7 @@ const type::Type* ModfResultVec::Match(MatchState& state, const type::Type* ty) std::string ModfResultVec::String(MatchState* state) const { const std::string N = state->NumName(); const std::string T = state->TypeName(); - std::stringstream ss; + utils::StringStream ss; ss << "__modf_result_vec" << N << "_" << T; return ss.str(); } @@ -1505,7 +1505,7 @@ const type::Type* FrexpResult::Match(MatchState& state, const type::Type* ty) co std::string FrexpResult::String(MatchState* state) const { const std::string T = state->TypeName(); - std::stringstream ss; + utils::StringStream ss; ss << "__frexp_result_" << T; return ss.str(); } @@ -1545,7 +1545,7 @@ const type::Type* FrexpResultVec::Match(MatchState& state, const type::Type* ty) std::string FrexpResultVec::String(MatchState* state) const { const std::string N = state->NumName(); const std::string T = state->TypeName(); - std::stringstream ss; + utils::StringStream ss; ss << "__frexp_result_vec" << N << "_" << T; return ss.str(); } @@ -1624,7 +1624,7 @@ const type::Type* Scalar::Match(MatchState& state, const type::Type* ty) const { } std::string Scalar::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); @@ -1667,7 +1667,7 @@ const type::Type* ConcreteScalar::Match(MatchState& state, const type::Type* ty) } std::string ConcreteScalar::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); @@ -1713,7 +1713,7 @@ const type::Type* ScalarNoF32::Match(MatchState& state, const type::Type* ty) co } std::string ScalarNoF32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << I32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); @@ -1759,7 +1759,7 @@ const type::Type* ScalarNoF16::Match(MatchState& state, const type::Type* ty) co } std::string ScalarNoF16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); @@ -1805,7 +1805,7 @@ const type::Type* ScalarNoI32::Match(MatchState& state, const type::Type* ty) co } std::string ScalarNoI32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << U32().String(nullptr) << " or " << Bool().String(nullptr); @@ -1851,7 +1851,7 @@ const type::Type* ScalarNoU32::Match(MatchState& state, const type::Type* ty) co } std::string ScalarNoU32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << Bool().String(nullptr); @@ -1897,7 +1897,7 @@ const type::Type* ScalarNoBool::Match(MatchState& state, const type::Type* ty) c } std::string ScalarNoBool::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << Fa().String(nullptr) << ", " << F32().String(nullptr) << ", " << F16().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); @@ -1943,7 +1943,7 @@ const type::Type* FiaFiu32F16::Match(MatchState& state, const type::Type* ty) co } std::string FiaFiu32F16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr); @@ -1986,7 +1986,7 @@ const type::Type* FiaFi32F16::Match(MatchState& state, const type::Type* ty) con } std::string FiaFi32F16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr); @@ -2029,7 +2029,7 @@ const type::Type* FiaFiu32::Match(MatchState& state, const type::Type* ty) const } std::string FiaFiu32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Fa().String(nullptr) << ", " << Ia().String(nullptr) << ", " << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); @@ -2063,7 +2063,7 @@ const type::Type* FaF32::Match(MatchState& state, const type::Type* ty) const { } std::string FaF32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Fa().String(nullptr) << " or " << F32().String(nullptr); @@ -2100,7 +2100,7 @@ const type::Type* FaF32F16::Match(MatchState& state, const type::Type* ty) const } std::string FaF32F16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Fa().String(nullptr) << ", " << F32().String(nullptr) << " or " << F16().String(nullptr); @@ -2137,7 +2137,7 @@ const type::Type* IaIu32::Match(MatchState& state, const type::Type* ty) const { } std::string IaIu32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); @@ -2171,7 +2171,7 @@ const type::Type* IaI32::Match(MatchState& state, const type::Type* ty) const { } std::string IaI32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << Ia().String(nullptr) << " or " << I32().String(nullptr); @@ -2211,7 +2211,7 @@ const type::Type* Fiu32F16::Match(MatchState& state, const type::Type* ty) const } std::string Fiu32F16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << F32().String(nullptr) << ", " << I32().String(nullptr) << ", " << U32().String(nullptr) << " or " << F16().String(nullptr); @@ -2248,7 +2248,7 @@ const type::Type* Fiu32::Match(MatchState& state, const type::Type* ty) const { } std::string Fiu32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << U32().String(nullptr); @@ -2285,7 +2285,7 @@ const type::Type* Fi32F16::Match(MatchState& state, const type::Type* ty) const } std::string Fi32F16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << F32().String(nullptr) << ", " << I32().String(nullptr) << " or " << F16().String(nullptr); @@ -2319,7 +2319,7 @@ const type::Type* Fi32::Match(MatchState& state, const type::Type* ty) const { } std::string Fi32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << F32().String(nullptr) << " or " << I32().String(nullptr); @@ -2353,7 +2353,7 @@ const type::Type* F32F16::Match(MatchState& state, const type::Type* ty) const { } std::string F32F16::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << F32().String(nullptr) << " or " << F16().String(nullptr); @@ -2387,7 +2387,7 @@ const type::Type* Iu32::Match(MatchState& state, const type::Type* ty) const { } std::string Iu32::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss << I32().String(nullptr) << " or " << U32().String(nullptr); diff --git a/src/tint/resolver/intrinsic_table.inl.tmpl b/src/tint/resolver/intrinsic_table.inl.tmpl index 92e7e31669..4769a3c609 100644 --- a/src/tint/resolver/intrinsic_table.inl.tmpl +++ b/src/tint/resolver/intrinsic_table.inl.tmpl @@ -221,7 +221,7 @@ std::string {{$class}}::String(MatchState*{{if .TemplateParams}} state{{end}}) c {{- end }} {{- if .DisplayName }} - std::stringstream ss; + utils::StringStream ss; ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}}; return ss.str(); {{- else if .TemplateParams }} @@ -264,7 +264,7 @@ const type::Type* {{$class}}::Match(MatchState& state, const type::Type* ty) con } std::string {{$class}}::String(MatchState*) const { - std::stringstream ss; + utils::StringStream ss; // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support // template arguments, nor can they match sub-types. As such, they have no use for the MatchState. ss diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 2d4950e278..6b116d9a16 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -84,6 +84,7 @@ #include "src/tint/utils/reverse.h" #include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/string.h" +#include "src/tint/utils/string_stream.h" #include "src/tint/utils/transform.h" #include "src/tint/utils/vector.h" @@ -3099,7 +3100,7 @@ sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) { filtered.Push(str); } } - std::ostringstream msg; + utils::StringStream msg; utils::SuggestAlternatives(unresolved->name, filtered.Slice().Reinterpret(), msg); AddNote(msg.str(), expr->source); @@ -3464,7 +3465,7 @@ bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) { if (rule != builtin::DiagnosticRule::kUndefined) { validator_.DiagnosticFilters().Set(rule, control.severity); } else { - std::ostringstream ss; + utils::StringStream ss; ss << "unrecognized diagnostic rule '" << rule_name << "'\n"; utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss); AddWarning(ss.str(), control.rule_name->source); @@ -3584,7 +3585,7 @@ type::Array* Resolver::Array(const Source& array_source, if (auto const_count = el_count->As()) { size = const_count->value * stride; if (size > std::numeric_limits::max()) { - std::stringstream msg; + utils::StringStream msg; msg << "array byte size (0x" << std::hex << size << ") must not exceed 0xffffffff bytes"; AddError(msg.str(), count_source); @@ -3822,7 +3823,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) { offset = utils::RoundUp(align, offset); if (offset > std::numeric_limits::max()) { - std::stringstream msg; + utils::StringStream msg; msg << "struct member offset (0x" << std::hex << offset << ") must not exceed 0x" << std::hex << std::numeric_limits::max() << " bytes"; AddError(msg.str(), member->source); @@ -3844,7 +3845,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) { struct_size = utils::RoundUp(struct_align, struct_size); if (struct_size > std::numeric_limits::max()) { - std::stringstream msg; + utils::StringStream msg; msg << "struct size (0x" << std::hex << struct_size << ") must not exceed 0xffffffff bytes"; AddError(msg.str(), str->source); return nullptr; @@ -4192,7 +4193,7 @@ bool Resolver::ApplyAddressSpaceUsageToType(builtin::AddressSpace address_space, if (decl && !ApplyAddressSpaceUsageToType( address_space, const_cast(member->Type()), decl->type->source)) { - std::stringstream err; + utils::StringStream err; err << "while analyzing structure member " << sem_.TypeNameOf(str) << "." << builder_->Symbols().NameFor(member->Name()); AddNote(err.str(), member->Source()); @@ -4223,7 +4224,7 @@ bool Resolver::ApplyAddressSpaceUsageToType(builtin::AddressSpace address_space, } if (builtin::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) { - std::stringstream err; + utils::StringStream err; err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in address space '" << address_space << "' as it is non-host-shareable"; AddError(err.str(), usage); @@ -4248,7 +4249,7 @@ SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback) return false; } } else { - std::ostringstream ss; + utils::StringStream ss; ss << "attribute is not valid for " << use; AddError(ss.str(), attr->source); return false; diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc index af8759a7f8..a601ef048a 100644 --- a/src/tint/resolver/resolver_test.cc +++ b/src/tint/resolver/resolver_test.cc @@ -46,6 +46,7 @@ #include "src/tint/type/reference.h" #include "src/tint/type/sampled_texture.h" #include "src/tint/type/texture_dimension.h" +#include "src/tint/utils/string_stream.h" using ::testing::ElementsAre; using ::testing::HasSubstr; @@ -1647,7 +1648,7 @@ TEST_P(Expr_Binary_Test_Valid, All) { ast::Type rhs_type = params.create_rhs_type(*this); auto* result_type = params.create_result_type(*this); - std::stringstream ss; + utils::StringStream ss; ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type); SCOPED_TRACE(ss.str()); @@ -1679,7 +1680,7 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) { ast::Type lhs_type = create_lhs_type(*this); ast::Type rhs_type = create_rhs_type(*this); - std::stringstream ss; + utils::StringStream ss; ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type); ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op << " " @@ -1728,7 +1729,7 @@ TEST_P(Expr_Binary_Test_Invalid, All) { ast::Type lhs_type = lhs_create_type_func(*this); ast::Type rhs_type = rhs_create_type_func(*this); - std::stringstream ss; + utils::StringStream ss; ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type); SCOPED_TRACE(ss.str()); diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc index 37fba4ce23..af43ce78b0 100644 --- a/src/tint/resolver/uniformity.cc +++ b/src/tint/resolver/uniformity.cc @@ -40,6 +40,7 @@ #include "src/tint/sem/while_statement.h" #include "src/tint/utils/block_allocator.h" #include "src/tint/utils/map.h" +#include "src/tint/utils/string_stream.h" #include "src/tint/utils/unique_vector.h" // Set to `1` to dump the uniformity graph for each function in graphviz format. @@ -1778,7 +1779,7 @@ class UniformityGraph { non_uniform_source->ast, [&](const ast::IdentifierExpression* ident) { auto* var = sem_.GetVal(ident)->UnwrapLoad()->As()->Variable(); - std::ostringstream ss; + utils::StringStream ss; if (auto* param = var->As()) { auto* func = param->Owner()->As(); ss << param_type(param) << "'" << NameFor(ident) << "' of '" << NameFor(func) @@ -1791,7 +1792,7 @@ class UniformityGraph { }, [&](const ast::Variable* v) { auto* var = sem_.Get(v); - std::ostringstream ss; + utils::StringStream ss; ss << "reading from " << var_type(var) << "'" << NameFor(v) << "' may result in a non-uniform value"; diagnostics_.add_note(diag::System::Resolver, ss.str(), v->source); @@ -1808,7 +1809,7 @@ class UniformityGraph { case Node::kFunctionCallArgumentContents: { auto* arg = c->args[non_uniform_source->arg_index]; auto* var = sem_.GetVal(arg)->RootIdentifier(); - std::ostringstream ss; + utils::StringStream ss; ss << "reading from " << var_type(var) << "'" << NameFor(var) << "' may result in a non-uniform value"; diagnostics_.add_note(diag::System::Resolver, ss.str(), @@ -1895,7 +1896,7 @@ class UniformityGraph { // Show the place where the non-uniform argument was passed. // If this is a builtin, this will be the trigger location for the failure. - std::ostringstream ss; + utils::StringStream ss; ss << "possibly non-uniform value passed" << (is_value ? "" : " via pointer") << " here"; report(call->args[cause->arg_index]->source, ss.str(), /* note */ user_func != nullptr); @@ -1907,7 +1908,7 @@ class UniformityGraph { { // Show a builtin was reachable from this call (which may be the call itself). // This will be the trigger location for the failure. - std::ostringstream ss; + utils::StringStream ss; ss << "'" << NameFor(builtin_call->target) << "' must only be called from uniform control flow"; report(builtin_call->source, ss.str(), /* note */ false); @@ -1915,7 +1916,7 @@ class UniformityGraph { if (builtin_call != call) { // The call was to a user function, so show that call too. - std::ostringstream ss; + utils::StringStream ss; ss << "called "; if (target->As() != SemCall(builtin_call)->Stmt()->Function()) { ss << "indirectly "; diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc index fec74b3b35..4fcacb6833 100644 --- a/src/tint/resolver/uniformity_test.cc +++ b/src/tint/resolver/uniformity_test.cc @@ -21,6 +21,7 @@ #include "src/tint/program_builder.h" #include "src/tint/reader/wgsl/parser.h" #include "src/tint/resolver/uniformity.h" +#include "src/tint/utils/string_stream.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -7890,7 +7891,7 @@ class UniformityAnalysisDiagnosticFilterTest TEST_P(UniformityAnalysisDiagnosticFilterTest, Directive) { auto& param = GetParam(); - std::ostringstream ss; + utils::StringStream ss; ss << "diagnostic(" << param << ", derivative_uniformity);" << R"( @group(0) @binding(0) var non_uniform : i32; @@ -7909,7 +7910,7 @@ fn foo() { if (param == builtin::DiagnosticSeverity::kOff) { EXPECT_TRUE(error_.empty()); } else { - std::ostringstream err; + utils::StringStream err; err << ToStr(param) << ": 'textureSample' must only be called"; EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); } @@ -7917,7 +7918,7 @@ fn foo() { TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) { auto& param = GetParam(); - std::ostringstream ss; + utils::StringStream ss; ss << R"( @group(0) @binding(0) var non_uniform : i32; @group(0) @binding(1) var t : texture_2d; @@ -7936,7 +7937,7 @@ TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) { if (param == builtin::DiagnosticSeverity::kOff) { EXPECT_TRUE(error_.empty()); } else { - std::ostringstream err; + utils::StringStream err; err << ToStr(param) << ": 'textureSample' must only be called"; EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); } @@ -7944,7 +7945,7 @@ TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnFunction) { TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnBlock) { auto& param = GetParam(); - std::ostringstream ss; + utils::StringStream ss; ss << R"( @group(0) @binding(0) var non_uniform : i32; @group(0) @binding(1) var t : texture_2d; @@ -7962,7 +7963,7 @@ fn foo() { if (param == builtin::DiagnosticSeverity::kOff) { EXPECT_TRUE(error_.empty()); } else { - std::ostringstream err; + utils::StringStream err; err << ToStr(param) << ": 'textureSample' must only be called"; EXPECT_THAT(error_, ::testing::HasSubstr(err.str())); } diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc index 6419999635..f8f4c4de42 100644 --- a/src/tint/resolver/validator.cc +++ b/src/tint/resolver/validator.cc @@ -71,6 +71,7 @@ #include "src/tint/utils/reverse.h" #include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/string.h" +#include "src/tint/utils/string_stream.h" #include "src/tint/utils/transform.h" namespace tint::resolver { @@ -380,7 +381,7 @@ bool Validator::VariableInitializer(const ast::Variable* v, // Value type has to match storage type if (storage_ty != value_type) { - std::stringstream s; + utils::StringStream s; s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty) << "' with value of type '" << sem_.TypeNameOf(initializer_ty) << "'"; AddError(s.str(), v->source); @@ -842,7 +843,7 @@ bool Validator::Parameter(const ast::Function* func, const sem::Variable* var) c break; } if (!ok) { - std::stringstream ss; + utils::StringStream ss; ss << "function parameter of pointer type cannot be in '" << sc << "' address space"; AddError(ss.str(), decl->source); @@ -870,7 +871,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, ast::PipelineStage stage, const bool is_input) const { auto* type = storage_ty->UnwrapRef(); - std::stringstream stage_name; + utils::StringStream stage_name; stage_name << stage; bool is_stage_mismatch = false; bool is_output = !is_input; @@ -883,7 +884,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!(type->is_float_vector() && type->As()->Width() == 4)) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'vec4'"; AddError(err.str(), attr->source); return false; @@ -898,7 +899,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!(type->is_unsigned_integer_vector() && type->As()->Width() == 3)) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'vec3'"; AddError(err.str(), attr->source); return false; @@ -910,7 +911,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!type->Is()) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'f32'"; AddError(err.str(), attr->source); return false; @@ -922,7 +923,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!type->Is()) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'bool'"; AddError(err.str(), attr->source); return false; @@ -934,7 +935,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!type->Is()) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'u32'"; AddError(err.str(), attr->source); return false; @@ -947,7 +948,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!type->Is()) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'u32'"; AddError(err.str(), attr->source); return false; @@ -958,7 +959,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!type->Is()) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'u32'"; AddError(err.str(), attr->source); return false; @@ -970,7 +971,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, is_stage_mismatch = true; } if (!type->Is()) { - std::stringstream err; + utils::StringStream err; err << "store type of @builtin(" << builtin << ") must be 'u32'"; AddError(err.str(), attr->source); return false; @@ -981,7 +982,7 @@ bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr, } if (is_stage_mismatch) { - std::stringstream err; + utils::StringStream err; err << "@builtin(" << builtin << ") cannot be used in " << (is_input ? "input of " : "output of ") << stage_name.str() << " pipeline stage"; AddError(err.str(), attr->source); @@ -1156,7 +1157,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage) pipeline_io_attribute = attr; if (builtins.Contains(builtin)) { - std::stringstream err; + utils::StringStream err; err << "@builtin(" << builtin << ") appears multiple times as pipeline " << (param_or_ret == ParamOrRetType::kParameter ? "input" : "output"); AddError(err.str(), decl->source); @@ -1949,7 +1950,7 @@ bool Validator::PipelineStages(utils::VectorRef entry_points) co if (stage != ast::PipelineStage::kCompute) { for (auto* var : func->DirectlyReferencedGlobals()) { if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) { - std::stringstream stage_name; + utils::StringStream stage_name; stage_name << stage; for (auto* user : var->Users()) { if (func == user->Stmt()->Function()) { @@ -1973,7 +1974,7 @@ bool Validator::PipelineStages(utils::VectorRef entry_points) co for (auto* builtin : func->DirectlyCalledBuiltins()) { if (!builtin->SupportedStages().Contains(stage)) { auto* call = func->FindDirectCallTo(builtin); - std::stringstream err; + utils::StringStream err; err << "built-in cannot be used by " << stage << " pipeline stage"; AddError(err.str(), call ? call->Declaration()->source : func->Declaration()->source); @@ -1987,7 +1988,7 @@ bool Validator::PipelineStages(utils::VectorRef entry_points) co auto check_no_discards = [&](const sem::Function* func, const sem::Function* entry_point) { if (auto* discard = func->DiscardStatement()) { auto stage = entry_point->Declaration()->PipelineStage(); - std::stringstream err; + utils::StringStream err; err << "discard statement cannot be used in " << stage << " pipeline stage"; AddError(err.str(), discard->Declaration()->source); backtrace(func, entry_point); @@ -2283,7 +2284,7 @@ bool Validator::LocationAttribute(const ast::LocationAttribute* loc_attr, } if (!locations.Add(location)) { - std::stringstream err; + utils::StringStream err; err << "@location(" << location << ") appears multiple times"; AddError(err.str(), loc_attr->source); return false; @@ -2543,12 +2544,12 @@ bool Validator::DiagnosticControls(utils::VectorRefrule_name->symbol, dc); if (!diag_added && (*diag_added.value)->severity != dc->severity) { { - std::ostringstream ss; + utils::StringStream ss; ss << "conflicting diagnostic " << use; AddError(ss.str(), dc->rule_name->source); } { - std::ostringstream ss; + utils::StringStream ss; ss << "severity of '" << symbols_.NameFor(dc->rule_name->symbol) << "' set to '" << dc->severity << "' here"; AddNote(ss.str(), (*diag_added.value)->rule_name->source); diff --git a/src/tint/resolver/value_constructor_validation_test.cc b/src/tint/resolver/value_constructor_validation_test.cc index 8ab1cab6e6..21603febe4 100644 --- a/src/tint/resolver/value_constructor_validation_test.cc +++ b/src/tint/resolver/value_constructor_validation_test.cc @@ -17,6 +17,7 @@ #include "src/tint/sem/value_constructor.h" #include "src/tint/sem/value_conversion.h" #include "src/tint/type/reference.h" +#include "src/tint/utils/string_stream.h" using namespace tint::number_suffixes; // NOLINT @@ -354,7 +355,7 @@ TEST_P(ConversionConstructorValidTest, All) { auto rhs_type = params.rhs_type(*this); auto* rhs_value_expr = params.rhs_value_expr(*this, 0); - std::stringstream ss; + utils::StringStream ss; ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "(" << FriendlyName(rhs_type) << "())"; SCOPED_TRACE(ss.str()); @@ -447,7 +448,7 @@ TEST_P(ConversionConstructorInvalidTest, All) { auto rhs_type = rhs_params.ast(*this); auto* rhs_value_expr = rhs_params.expr_from_double(*this, 0); - std::stringstream ss; + utils::StringStream ss; ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "(" << FriendlyName(rhs_type) << "())"; SCOPED_TRACE(ss.str()); @@ -2414,7 +2415,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewArguments) { Enable(builtin::Extension::kF16); const std::string element_type_name = param.get_element_type_name(); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns - 1; i++) { ast::Type vec_type = param.create_column_ast_type(*this); @@ -2443,7 +2444,7 @@ TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooFewArguments) { Enable(builtin::Extension::kF16); const std::string element_type_name = param.get_element_type_name(); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns * param.rows - 1; i++) { args.Push(Call(param.create_element_ast_type(*this))); @@ -2471,7 +2472,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyArguments) { Enable(builtin::Extension::kF16); const std::string element_type_name = param.get_element_type_name(); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns + 1; i++) { ast::Type vec_type = param.create_column_ast_type(*this); @@ -2500,7 +2501,7 @@ TEST_P(MatrixConstructorTest, ElementConstructor_Error_TooManyArguments) { Enable(builtin::Extension::kF16); const std::string element_type_name = param.get_element_type_name(); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns * param.rows + 1; i++) { args.Push(Call(param.create_element_ast_type(*this))); @@ -2527,7 +2528,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_InvalidArgumentType) { Enable(builtin::Extension::kF16); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns; i++) { auto vec_type = ty.vec(param.rows); @@ -2555,7 +2556,7 @@ TEST_P(MatrixConstructorTest, ElementConstructor_Error_InvalidArgumentType) { Enable(builtin::Extension::kF16); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns; i++) { args.Push(Expr(1_u)); @@ -2588,7 +2589,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooFewRowsInVectorArgument Enable(builtin::Extension::kF16); const std::string element_type_name = param.get_element_type_name(); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns; i++) { ast::Type valid_vec_type = param.create_column_ast_type(*this); @@ -2626,7 +2627,7 @@ TEST_P(MatrixConstructorTest, ColumnConstructor_Error_TooManyRowsInVectorArgumen Enable(builtin::Extension::kF16); const std::string element_type_name = param.get_element_type_name(); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns; i++) { ast::Type valid_vec_type = param.create_column_ast_type(*this); @@ -2715,7 +2716,7 @@ TEST_P(MatrixConstructorTest, ElementTypeAlias_Error) { auto* elem_type_alias = Alias("ElemType", param.create_element_ast_type(*this)); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns; i++) { auto vec_type = ty.vec(ty.u32(), param.rows); @@ -2797,7 +2798,7 @@ TEST_P(MatrixConstructorTest, ArgumentElementTypeAlias_Error) { ast::Type matrix_type = param.create_mat_ast_type(*this); auto* u32_type_alias = Alias("UnsignedInt", ty.u32()); - std::stringstream args_tys; + utils::StringStream args_tys; utils::Vector args; for (uint32_t i = 0; i < param.columns; i++) { auto vec_type = ty.vec(ty.Of(u32_type_alias), param.rows); @@ -2874,7 +2875,7 @@ TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) { Enable(builtin::Extension::kF16); - std::stringstream err; + utils::StringStream err; err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows << "("; @@ -2905,7 +2906,7 @@ TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) { Enable(builtin::Extension::kF16); - std::stringstream err; + utils::StringStream err; err << "12:34 error: no matching constructor for mat" << param.columns << "x" << param.rows << "("; @@ -3073,7 +3074,7 @@ TEST_P(StructConstructorTypeTest, AllTypes) { auto* tc = Call(ty.Of(s), values); WrapInFunction(tc); - std::stringstream err; + utils::StringStream err; err << "error: type in structure constructor does not match struct member "; err << "type: expected '" << str_params.name() << "', found '" << ctor_params.name() << "'"; EXPECT_FALSE(r()->Resolve()); diff --git a/src/tint/utils/string.cc b/src/tint/utils/string.cc index bccd52c23a..2f28a3e055 100644 --- a/src/tint/utils/string.cc +++ b/src/tint/utils/string.cc @@ -50,7 +50,7 @@ size_t Distance(std::string_view str_a, std::string_view str_b) { void SuggestAlternatives(std::string_view got, Slice strings, - std::ostringstream& ss) { + utils::StringStream& ss) { // If the string typed was within kSuggestionDistance of one of the possible enum values, // suggest that. Don't bother with suggestions if the string was extremely long. constexpr size_t kSuggestionDistance = 5; diff --git a/src/tint/utils/string.h b/src/tint/utils/string.h index 08e0be3138..9bf6e7a5b0 100644 --- a/src/tint/utils/string.h +++ b/src/tint/utils/string.h @@ -20,6 +20,7 @@ #include #include "src/tint/utils/slice.h" +#include "src/tint/utils/string_stream.h" namespace tint::utils { @@ -74,7 +75,7 @@ size_t Distance(std::string_view a, std::string_view b); /// @param ss the stream to write the suggest and list of possible values to void SuggestAlternatives(std::string_view got, Slice strings, - std::ostringstream& ss); + utils::StringStream& ss); } // namespace tint::utils diff --git a/src/tint/utils/string_test.cc b/src/tint/utils/string_test.cc index b9e1ebb842..0f351cff9b 100644 --- a/src/tint/utils/string_test.cc +++ b/src/tint/utils/string_test.cc @@ -15,6 +15,7 @@ #include "src/tint/utils/string.h" #include "gtest/gtest.h" +#include "src/tint/utils/string_stream.h" namespace tint::utils { namespace { @@ -61,14 +62,14 @@ TEST(StringTest, Distance) { TEST(StringTest, SuggestAlternatives) { { const char* alternatives[] = {"hello world", "Hello World"}; - std::ostringstream ss; + utils::StringStream ss; SuggestAlternatives("hello wordl", alternatives, ss); EXPECT_EQ(ss.str(), R"(Did you mean 'hello world'? Possible values: 'hello world', 'Hello World')"); } { const char* alternatives[] = {"foobar", "something else"}; - std::ostringstream ss; + utils::StringStream ss; SuggestAlternatives("hello world", alternatives, ss); EXPECT_EQ(ss.str(), R"(Possible values: 'foobar', 'something else')"); }