Convert GLSL Generator over to utils::StringStream.

This CL switches the GLSL Generator to use utils::StringStream. The line
writer is converted internally as well, although it converts to
`std::ostream` for now. This caused a couple of the MSL, HLSL and GLSL
tests to generate slightly fewer decimal points in a couple tests.

Bug: tint:1686
Change-Id: I9ec8c1a5ef49679fc1c9a9aece86ab3390e103fc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121880
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/utils/string_stream.h b/src/tint/utils/string_stream.h
index c4ce53a..5bf9faa 100644
--- a/src/tint/utils/string_stream.h
+++ b/src/tint/utils/string_stream.h
@@ -96,6 +96,10 @@
     /// @returns the string contents of the stream
     std::string str() const { return sstream_.str(); }
 
+    /// [DEPRECATED] This should not be called.
+    /// @returns the underlying stream
+    std::ostream& stream() { return sstream_; }
+
   private:
     std::stringstream sstream_;
 };
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index e8b5b9b..199990a 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -75,6 +75,7 @@
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/scoped_assignment.h"
 #include "src/tint/utils/string.h"
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/append_vector.h"
 #include "src/tint/writer/float_to_string.h"
 #include "src/tint/writer/generate_external_texture_bindings.h"
@@ -111,7 +112,7 @@
     return IsAnyOf<ast::BreakStatement>(stmts->Last());
 }
 
-void PrintF32(std::ostream& out, float value) {
+void PrintF32(utils::StringStream& out, float value) {
     if (std::isinf(value)) {
         out << "0.0f " << (value >= 0 ? "/* inf */" : "/* -inf */");
     } else if (std::isnan(value)) {
@@ -121,7 +122,7 @@
     }
 }
 
-void PrintF16(std::ostream& out, float value) {
+void PrintF16(utils::StringStream& out, float value) {
     if (std::isinf(value)) {
         out << "0.0hf " << (value >= 0 ? "/* inf */" : "/* -inf */");
     } else if (std::isnan(value)) {
@@ -333,7 +334,8 @@
     return true;
 }
 
-bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+bool GeneratorImpl::EmitIndexAccessor(utils::StringStream& out,
+                                      const ast::IndexAccessorExpression* expr) {
     if (!EmitExpression(out, expr->object)) {
         return false;
     }
@@ -347,7 +349,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+bool GeneratorImpl::EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr) {
     auto* src_type = TypeOf(expr->expr)->UnwrapRef();
     auto* dst_type = TypeOf(expr)->UnwrapRef();
 
@@ -379,7 +381,7 @@
             return false;
         }
     }
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
     if (!EmitExpression(out, expr->expr)) {
         return false;
     }
@@ -399,7 +401,8 @@
     return true;
 }
 
-bool GeneratorImpl::EmitVectorRelational(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitVectorRelational(utils::StringStream& out,
+                                         const ast::BinaryExpression* expr) {
     switch (expr->op) {
         case ast::BinaryOp::kEqual:
             out << "equal";
@@ -422,7 +425,7 @@
         default:
             break;
     }
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
     if (!EmitExpression(out, expr->lhs)) {
         return false;
     }
@@ -433,7 +436,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBitwiseBoolOp(utils::StringStream& out, const ast::BinaryExpression* expr) {
     auto* bool_type = TypeOf(expr->lhs)->UnwrapRef();
     auto* uint_type = BoolTypeToUint(bool_type);
 
@@ -442,14 +445,14 @@
                   "")) {
         return false;
     }
-    ScopedParen outerCastParen(out);
+    ScopedParen outerCastParen(out.stream());
     // Cast LHS to uint scalar or vector type.
     if (!EmitType(out, uint_type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
                   "")) {
         return false;
     }
     {
-        ScopedParen innerCastParen(out);
+        ScopedParen innerCastParen(out.stream());
         // Emit LHS.
         if (!EmitExpression(out, expr->lhs)) {
             return false;
@@ -470,7 +473,7 @@
         return false;
     }
     {
-        ScopedParen innerCastParen(out);
+        ScopedParen innerCastParen(out.stream());
         // Emit RHS.
         if (!EmitExpression(out, expr->rhs)) {
             return false;
@@ -479,7 +482,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitFloatModulo(utils::StringStream& out, const ast::BinaryExpression* expr) {
     std::string fn;
     auto* ret_ty = TypeOf(expr)->UnwrapRef();
     auto* lhs_ty = TypeOf(expr->lhs)->UnwrapRef();
@@ -529,7 +532,7 @@
     // Call the helper
     out << fn;
     {
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
         if (!EmitExpression(out, expr->lhs)) {
             return false;
         }
@@ -541,7 +544,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+bool GeneratorImpl::EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr) {
     if (IsRelational(expr->op) && !TypeOf(expr->lhs)->UnwrapRef()->is_scalar()) {
         return EmitVectorRelational(out, expr);
     }
@@ -589,7 +592,7 @@
         return EmitFloatModulo(out, expr);
     }
 
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
     if (!EmitExpression(out, expr->lhs)) {
         return false;
     }
@@ -706,7 +709,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCall(utils::StringStream& out, const ast::CallExpression* expr) {
     auto* call = builder_.Sem().Get<sem::Call>(expr);
     return Switch(
         call->Target(),  //
@@ -721,14 +724,14 @@
         });
 }
 
-bool GeneratorImpl::EmitFunctionCall(std::ostream& out,
+bool GeneratorImpl::EmitFunctionCall(utils::StringStream& out,
                                      const sem::Call* call,
                                      const sem::Function* fn) {
     const auto& args = call->Arguments();
     auto* ident = fn->Declaration()->name;
 
     out << builder_.Symbols().NameFor(ident->symbol);
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
 
     bool first = true;
     for (auto* arg : args) {
@@ -745,7 +748,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
+bool GeneratorImpl::EmitBuiltinCall(utils::StringStream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
     auto* expr = call->Declaration();
@@ -810,7 +813,7 @@
     }
 
     out << name;
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
 
     bool first = true;
     for (auto* arg : call->Arguments()) {
@@ -827,14 +830,14 @@
     return true;
 }
 
-bool GeneratorImpl::EmitValueConversion(std::ostream& out,
+bool GeneratorImpl::EmitValueConversion(utils::StringStream& out,
                                         const sem::Call* call,
                                         const sem::ValueConversion* conv) {
     if (!EmitType(out, conv->Target(), builtin::AddressSpace::kUndefined,
                   builtin::Access::kReadWrite, "")) {
         return false;
     }
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
 
     if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
         return false;
@@ -843,7 +846,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitValueConstructor(std::ostream& out,
+bool GeneratorImpl::EmitValueConstructor(utils::StringStream& out,
                                          const sem::Call* call,
                                          const sem::ValueConstructor* ctor) {
     auto* type = ctor->ReturnType();
@@ -857,7 +860,7 @@
     if (!EmitType(out, type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, "")) {
         return false;
     }
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
 
     bool first = true;
     for (auto* arg : call->Arguments()) {
@@ -874,13 +877,13 @@
     return true;
 }
 
-bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
+bool GeneratorImpl::EmitWorkgroupAtomicCall(utils::StringStream& out,
                                             const ast::CallExpression* expr,
                                             const sem::Builtin* builtin) {
     auto call = [&](const char* name) {
         out << name;
         {
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
             for (size_t i = 0; i < expr->args.Length(); i++) {
                 auto* arg = expr->args[i];
                 if (i > 0) {
@@ -900,7 +903,7 @@
             // atomicOr using 0 as the OR value
             out << "atomicOr";
             {
-                ScopedParen sp(out);
+                ScopedParen sp(out.stream());
                 if (!EmitExpression(out, expr->args[0])) {
                     return false;
                 }
@@ -995,7 +998,7 @@
     return false;
 }
 
-bool GeneratorImpl::EmitArrayLength(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitArrayLength(utils::StringStream& out, const ast::CallExpression* expr) {
     out << "uint(";
     if (!EmitExpression(out, expr->args[0])) {
         return false;
@@ -1004,7 +1007,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitExtractBits(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitExtractBits(utils::StringStream& out, const ast::CallExpression* expr) {
     out << "bitfieldExtract(";
     if (!EmitExpression(out, expr->args[0])) {
         return false;
@@ -1021,7 +1024,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitInsertBits(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitInsertBits(utils::StringStream& out, const ast::CallExpression* expr) {
     out << "bitfieldInsert(";
     if (!EmitExpression(out, expr->args[0])) {
         return false;
@@ -1042,7 +1045,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitEmulatedFMA(utils::StringStream& out, const ast::CallExpression* expr) {
     out << "((";
     if (!EmitExpression(out, expr->args[0])) {
         return false;
@@ -1059,7 +1062,8 @@
     return true;
 }
 
-bool GeneratorImpl::EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitCountOneBitsCall(utils::StringStream& out,
+                                         const ast::CallExpression* expr) {
     // GLSL's bitCount returns an integer type, so cast it to the appropriate
     // unsigned type.
     if (!EmitType(out, TypeOf(expr)->UnwrapRef(), builtin::AddressSpace::kUndefined,
@@ -1075,7 +1079,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitSelectCall(std::ostream& out, const ast::CallExpression* expr) {
+bool GeneratorImpl::EmitSelectCall(utils::StringStream& out, const ast::CallExpression* expr) {
     auto* expr_false = expr->args[0];
     auto* expr_true = expr->args[1];
     auto* expr_cond = expr->args[2];
@@ -1097,7 +1101,7 @@
         out << ")";
         return true;
     }
-    ScopedParen paren(out);
+    ScopedParen paren(out.stream());
     if (!EmitExpression(out, expr_cond)) {
         return false;
     }
@@ -1117,7 +1121,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitDotCall(std::ostream& out,
+bool GeneratorImpl::EmitDotCall(utils::StringStream& out,
                                 const ast::CallExpression* expr,
                                 const sem::Builtin* builtin) {
     auto* vec_ty = builtin->Parameters()[0]->Type()->As<type::Vector>();
@@ -1133,7 +1137,7 @@
 
             std::string v;
             {
-                std::stringstream s;
+                utils::StringStream s;
                 if (!EmitType(s, vec_ty->type(), builtin::AddressSpace::kUndefined,
                               builtin::Access::kRead, "")) {
                     return "";
@@ -1178,7 +1182,7 @@
     }
 
     out << fn;
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
 
     if (!EmitExpression(out, expr->args[0])) {
         return false;
@@ -1190,7 +1194,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitModfCall(std::ostream& out,
+bool GeneratorImpl::EmitModfCall(utils::StringStream& out,
                                  const ast::CallExpression* expr,
                                  const sem::Builtin* builtin) {
     TINT_ASSERT(Writer, expr->args.Length() == 1);
@@ -1216,7 +1220,7 @@
         });
 }
 
-bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
+bool GeneratorImpl::EmitFrexpCall(utils::StringStream& out,
                                   const ast::CallExpression* expr,
                                   const sem::Builtin* builtin) {
     TINT_ASSERT(Writer, expr->args.Length() == 1);
@@ -1242,7 +1246,7 @@
         });
 }
 
-bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
+bool GeneratorImpl::EmitDegreesCall(utils::StringStream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
     auto* return_elem_type = type::Type::DeepestElementOf(builtin->ReturnType());
@@ -1255,7 +1259,7 @@
                              });
 }
 
-bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
+bool GeneratorImpl::EmitRadiansCall(utils::StringStream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
     auto* return_elem_type = type::Type::DeepestElementOf(builtin->ReturnType());
@@ -1268,7 +1272,7 @@
                              });
 }
 
-bool GeneratorImpl::EmitQuantizeToF16Call(std::ostream& out,
+bool GeneratorImpl::EmitQuantizeToF16Call(utils::StringStream& out,
                                           const ast::CallExpression* expr,
                                           const sem::Builtin* builtin) {
     // Emulate by casting to f16 and back again.
@@ -1300,7 +1304,7 @@
         });
 }
 
-bool GeneratorImpl::EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin) {
+bool GeneratorImpl::EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
     if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
@@ -1325,7 +1329,7 @@
     return zero;
 }
 
-bool GeneratorImpl::EmitTextureCall(std::ostream& out,
+bool GeneratorImpl::EmitTextureCall(utils::StringStream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
     using Usage = sem::ParameterUsage;
@@ -1374,7 +1378,7 @@
             return EmitExpression(out, e);
         }
         emit_signed_int_type(ty);
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
         return EmitExpression(out, e);
     };
 
@@ -1384,7 +1388,7 @@
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
             emit_unsigned_int_type(call->Type());
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             if (texture_type->Is<type::StorageTexture>()) {
                 out << "imageSize(";
@@ -1423,7 +1427,7 @@
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
             out << "uint";
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             if (texture_type->Is<type::StorageTexture>()) {
                 out << "imageSize(";
@@ -1457,7 +1461,7 @@
             // textureQueryLevels() returns a signed scalar in GLSL.
             // Cast.
             out << "uint";
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             out << "textureQueryLevels(";
             if (!EmitExpression(out, texture)) {
@@ -1471,7 +1475,7 @@
             // textureSamples() returns a signed scalar in GLSL.
             // Cast.
             out << "uint";
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             out << "textureSamples(";
             if (!EmitExpression(out, texture)) {
@@ -1818,7 +1822,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+bool GeneratorImpl::EmitExpression(utils::StringStream& out, const ast::Expression* expr) {
     if (auto* sem = builder_.Sem().GetVal(expr)) {
         if (auto* constant = sem->ConstantValue()) {
             return EmitConstant(out, constant);
@@ -1841,7 +1845,8 @@
         });
 }
 
-bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+bool GeneratorImpl::EmitIdentifier(utils::StringStream& out,
+                                   const ast::IdentifierExpression* expr) {
     out << builder_.Symbols().NameFor(expr->identifier->symbol);
     return true;
 }
@@ -2187,7 +2192,7 @@
 }
 
 void GeneratorImpl::EmitInterpolationQualifiers(
-    std::ostream& out,
+    utils::StringStream& out,
     utils::VectorRef<const ast::Attribute*> attributes) {
     for (auto* attr : attributes) {
         if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
@@ -2223,7 +2228,7 @@
     }
 }
 
-bool GeneratorImpl::EmitAttributes(std::ostream& out,
+bool GeneratorImpl::EmitAttributes(utils::StringStream& out,
                                    const sem::GlobalVariable* var,
                                    utils::VectorRef<const ast::Attribute*> attributes) {
     if (attributes.IsEmpty()) {
@@ -2333,7 +2338,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitConstant(std::ostream& out, const constant::Value* constant) {
+bool GeneratorImpl::EmitConstant(utils::StringStream& out, const constant::Value* constant) {
     return Switch(
         constant->Type(),  //
         [&](const type::Bool*) {
@@ -2362,7 +2367,7 @@
                 return false;
             }
 
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             if (constant->AllEqual()) {
                 return EmitConstant(out, constant->Index(0));
@@ -2384,7 +2389,7 @@
                 return false;
             }
 
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             for (size_t column_idx = 0; column_idx < m->columns(); column_idx++) {
                 if (column_idx > 0) {
@@ -2402,7 +2407,7 @@
                 return false;
             }
 
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             auto count = a->ConstantCount();
             if (!count) {
@@ -2429,7 +2434,7 @@
 
             out << StructName(s);
 
-            ScopedParen sp(out);
+            ScopedParen sp(out.stream());
 
             for (size_t i = 0; i < s->Members().Length(); i++) {
                 if (i > 0) {
@@ -2450,7 +2455,7 @@
         });
 }
 
-bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+bool GeneratorImpl::EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit) {
     return Switch(
         lit,
         [&](const ast::BoolLiteralExpression* l) {
@@ -2478,7 +2483,7 @@
         });
 }
 
-bool GeneratorImpl::EmitZeroValue(std::ostream& out, const type::Type* type) {
+bool GeneratorImpl::EmitZeroValue(utils::StringStream& out, const type::Type* type) {
     if (type->Is<type::Bool>()) {
         out << "false";
     } else if (type->Is<type::F32>()) {
@@ -2494,7 +2499,7 @@
                       "")) {
             return false;
         }
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
         for (uint32_t i = 0; i < vec->Width(); i++) {
             if (i != 0) {
                 out << ", ";
@@ -2508,7 +2513,7 @@
                       "")) {
             return false;
         }
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
         for (uint32_t i = 0; i < (mat->rows() * mat->columns()); i++) {
             if (i != 0) {
                 out << ", ";
@@ -2523,7 +2528,7 @@
             return false;
         }
         bool first = true;
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
         for (auto* member : str->Members()) {
             if (!first) {
                 out << ", ";
@@ -2537,7 +2542,7 @@
                       "")) {
             return false;
         }
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
 
         auto count = arr->ConstantCount();
         if (!count) {
@@ -2604,7 +2609,7 @@
     }
 
     TextBuffer cond_pre;
-    std::stringstream cond_buf;
+    utils::StringStream cond_buf;
     if (auto* cond = stmt->condition) {
         TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
         if (!EmitExpression(cond_buf, cond)) {
@@ -2696,7 +2701,7 @@
 
 bool GeneratorImpl::EmitWhile(const ast::WhileStatement* stmt) {
     TextBuffer cond_pre;
-    std::stringstream cond_buf;
+    utils::StringStream cond_buf;
     {
         auto* cond = stmt->condition;
         TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
@@ -2745,7 +2750,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+bool GeneratorImpl::EmitMemberAccessor(utils::StringStream& out,
                                        const ast::MemberAccessorExpression* expr) {
     if (!EmitExpression(out, expr->object)) {
         return false;
@@ -2857,7 +2862,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitType(std::ostream& out,
+bool GeneratorImpl::EmitType(utils::StringStream& out,
                              const type::Type* type,
                              builtin::AddressSpace address_space,
                              builtin::Access access,
@@ -3038,7 +3043,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
+bool GeneratorImpl::EmitTypeAndName(utils::StringStream& out,
                                     const type::Type* type,
                                     builtin::AddressSpace address_space,
                                     builtin::Access access,
@@ -3086,7 +3091,7 @@
     return true;
 }
 
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+bool GeneratorImpl::EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr) {
     switch (expr->op) {
         case ast::UnaryOp::kIndirection:
         case ast::UnaryOp::kAddressOf:
@@ -3106,7 +3111,7 @@
             break;
     }
 
-    ScopedParen sp(out);
+    ScopedParen sp(out.stream());
     if (!EmitExpression(out, expr->expr)) {
         return false;
     }
@@ -3182,7 +3187,7 @@
 }
 
 template <typename F>
-bool GeneratorImpl::CallBuiltinHelper(std::ostream& out,
+bool GeneratorImpl::CallBuiltinHelper(utils::StringStream& out,
                                       const ast::CallExpression* call,
                                       const sem::Builtin* builtin,
                                       F&& build) {
@@ -3238,7 +3243,7 @@
     // Call the helper
     out << fn;
     {
-        ScopedParen sp(out);
+        ScopedParen sp(out.stream());
         bool first = true;
         for (auto* arg : call->args) {
             if (!first) {
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index d220877..d954921 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -37,6 +37,7 @@
 #include "src/tint/scope_stack.h"
 #include "src/tint/transform/decompose_memory_access.h"
 #include "src/tint/utils/hash.h"
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/generator.h"
 #include "src/tint/writer/glsl/version.h"
 #include "src/tint/writer/text_generator.h"
@@ -93,7 +94,7 @@
     /// @param out the output of the expression stream
     /// @param expr the expression to emit
     /// @returns true if the index accessor was emitted
-    bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+    bool EmitIndexAccessor(utils::StringStream& out, const ast::IndexAccessorExpression* expr);
     /// Handles an assignment statement
     /// @param stmt the statement to emit
     /// @returns true if the statement was emitted successfully
@@ -102,27 +103,27 @@
     /// @param out the output of the expression stream
     /// @param expr the binary expression
     /// @returns true if the expression was emitted, false otherwise
-    bool EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr);
+    bool EmitBitwiseBoolOp(utils::StringStream& out, const ast::BinaryExpression* expr);
     /// Handles generating a binary expression
     /// @param out the output of the expression stream
     /// @param expr the binary expression
     /// @returns true if the expression was emitted, false otherwise
-    bool EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr);
+    bool EmitFloatModulo(utils::StringStream& out, const ast::BinaryExpression* expr);
     /// Handles generating the modulo operator on float vector operands
     /// @param out the output of the expression stream
     /// @param expr the binary expression
     /// @returns true if the expression was emitted, false otherwise
-    bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+    bool EmitBinary(utils::StringStream& out, const ast::BinaryExpression* expr);
     /// Handles generating a bitcast expression
     /// @param out the output of the expression stream
     /// @param expr the expression
     /// @returns true if the binary expression was emitted
-    bool EmitVectorRelational(std::ostream& out, const ast::BinaryExpression* expr);
+    bool EmitVectorRelational(utils::StringStream& out, const ast::BinaryExpression* expr);
     /// Handles generating a vector relational expression
     /// @param out the output of the expression stream
     /// @param expr the expression
     /// @returns true if the vector relational expression was emitted
-    bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+    bool EmitBitcast(utils::StringStream& out, const ast::BitcastExpression* expr);
     /// Emits a list of statements
     /// @param stmts the statement list
     /// @returns true if the statements were emitted successfully
@@ -147,25 +148,27 @@
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @returns true if the call expression is emitted
-    bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitCall(utils::StringStream& out, const ast::CallExpression* expr);
     /// Handles generating a function call expression
     /// @param out the output of the expression stream
     /// @param call the call expression
     /// @param fn the function being called
     /// @returns true if the expression is emitted
-    bool EmitFunctionCall(std::ostream& out, const sem::Call* call, const sem::Function* fn);
+    bool EmitFunctionCall(utils::StringStream& out, const sem::Call* call, const sem::Function* fn);
     /// Handles generating a builtin call expression
     /// @param out the output of the expression stream
     /// @param call the call expression
     /// @param builtin the builtin being called
     /// @returns true if the expression is emitted
-    bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitBuiltinCall(utils::StringStream& out,
+                         const sem::Call* call,
+                         const sem::Builtin* builtin);
     /// Handles generating a value conversion expression
     /// @param out the output of the expression stream
     /// @param call the call expression
     /// @param conv the value conversion
     /// @returns true if the expression is emitted
-    bool EmitValueConversion(std::ostream& out,
+    bool EmitValueConversion(utils::StringStream& out,
                              const sem::Call* call,
                              const sem::ValueConversion* conv);
     /// Handles generating a value constructor expression
@@ -173,42 +176,42 @@
     /// @param call the call expression
     /// @param ctor the value constructor
     /// @returns true if the expression is emitted
-    bool EmitValueConstructor(std::ostream& out,
+    bool EmitValueConstructor(utils::StringStream& out,
                               const sem::Call* call,
                               const sem::ValueConstructor* ctor);
     /// Handles generating a barrier builtin call
     /// @param out the output of the expression stream
     /// @param builtin the semantic information for the barrier builtin
     /// @returns true if the call expression is emitted
-    bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
+    bool EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin);
     /// Handles generating an atomic builtin call for a workgroup variable
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the atomic builtin
     /// @returns true if the call expression is emitted
-    bool EmitWorkgroupAtomicCall(std::ostream& out,
+    bool EmitWorkgroupAtomicCall(utils::StringStream& out,
                                  const ast::CallExpression* expr,
                                  const sem::Builtin* builtin);
     /// Handles generating an array.length() call
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @returns true if the array length expression is emitted
-    bool EmitArrayLength(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitArrayLength(utils::StringStream& out, const ast::CallExpression* expr);
     /// Handles generating a call to `bitfieldExtract`
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @returns true if the expression is emitted
-    bool EmitExtractBits(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitExtractBits(utils::StringStream& out, const ast::CallExpression* expr);
     /// Handles generating a call to `bitfieldInsert`
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @returns true if the expression is emitted
-    bool EmitInsertBits(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitInsertBits(utils::StringStream& out, const ast::CallExpression* expr);
     /// Emulates 'fma' on GLSL ES, where it is unsupported.
     /// @param out the output of the expression stream
     /// @param expr the fma() expression
     /// @returns true if the expression is emitted
-    bool EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitEmulatedFMA(utils::StringStream& out, const ast::CallExpression* expr);
     /// Create a float literal zero AST node, and associated semantic nodes.
     /// @param stmt the statement which will own the semantic expression node
     /// @returns an AST expression representing 0.0f
@@ -220,23 +223,25 @@
     /// @param call the call expression
     /// @param builtin the semantic information for the texture builtin
     /// @returns true if the call expression is emitted
-    bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitTextureCall(utils::StringStream& out,
+                         const sem::Call* call,
+                         const sem::Builtin* builtin);
     /// Handles generating a call to the `select()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @returns true if the call expression is emitted
-    bool EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitCountOneBitsCall(utils::StringStream& out, const ast::CallExpression* expr);
     /// Handles generating a call to the `countOneBits()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @returns true if the call expression is emitted
-    bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
+    bool EmitSelectCall(utils::StringStream& out, const ast::CallExpression* expr);
     /// Handles generating a call to the `dot()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitDotCall(std::ostream& out,
+    bool EmitDotCall(utils::StringStream& out,
                      const ast::CallExpression* expr,
                      const sem::Builtin* builtin);
     /// Handles generating a call to the `modf()` builtin
@@ -244,7 +249,7 @@
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitModfCall(std::ostream& out,
+    bool EmitModfCall(utils::StringStream& out,
                       const ast::CallExpression* expr,
                       const sem::Builtin* builtin);
     /// Handles generating a call to the `frexp()` builtin
@@ -252,7 +257,7 @@
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitFrexpCall(std::ostream& out,
+    bool EmitFrexpCall(utils::StringStream& out,
                        const ast::CallExpression* expr,
                        const sem::Builtin* builtin);
     /// Handles generating a call to the `degrees()` builtin
@@ -260,7 +265,7 @@
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitDegreesCall(std::ostream& out,
+    bool EmitDegreesCall(utils::StringStream& out,
                          const ast::CallExpression* expr,
                          const sem::Builtin* builtin);
     /// Handles generating a call to the `radians()` builtin
@@ -268,7 +273,7 @@
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitRadiansCall(std::ostream& out,
+    bool EmitRadiansCall(utils::StringStream& out,
                          const ast::CallExpression* expr,
                          const sem::Builtin* builtin);
     /// Handles generating a call to the `quantizeToF16()` intrinsic
@@ -276,7 +281,7 @@
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitQuantizeToF16Call(std::ostream& out,
+    bool EmitQuantizeToF16Call(utils::StringStream& out,
                                const ast::CallExpression* expr,
                                const sem::Builtin* builtin);
     /// Handles a case statement
@@ -295,7 +300,7 @@
     /// @param out the output of the expression stream
     /// @param expr the expression
     /// @returns true if the expression was emitted
-    bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+    bool EmitExpression(utils::StringStream& out, const ast::Expression* expr);
     /// Handles generating a function
     /// @param func the function to generate
     /// @returns true if the function was emitted
@@ -342,14 +347,14 @@
     /// Handles emitting interpolation qualifiers
     /// @param out the output of the expression stream
     /// @param attrs the attributes
-    void EmitInterpolationQualifiers(std::ostream& out,
+    void EmitInterpolationQualifiers(utils::StringStream& out,
                                      utils::VectorRef<const ast::Attribute*> attrs);
     /// Handles emitting attributes
     /// @param out the output of the expression stream
     /// @param var the global variable semantics
     /// @param attrs the attributes
     /// @returns true if the attributes were emitted
-    bool EmitAttributes(std::ostream& out,
+    bool EmitAttributes(utils::StringStream& out,
                         const sem::GlobalVariable* var,
                         utils::VectorRef<const ast::Attribute*> attrs);
     /// Handles emitting the entry point function
@@ -364,12 +369,12 @@
     /// @param out the output stream
     /// @param constant the constant value to emit
     /// @returns true if the constant value was successfully emitted
-    bool EmitConstant(std::ostream& out, const constant::Value* constant);
+    bool EmitConstant(utils::StringStream& out, const constant::Value* constant);
     /// Handles a literal
     /// @param out the output stream
     /// @param lit the literal to emit
     /// @returns true if the literal was successfully emitted
-    bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+    bool EmitLiteral(utils::StringStream& out, const ast::LiteralExpression* lit);
     /// Handles a loop statement
     /// @param stmt the statement to emit
     /// @returns true if the statement was emitted
@@ -386,12 +391,12 @@
     /// @param out the output of the expression stream
     /// @param expr the identifier expression
     /// @returns true if the identifier was emitted
-    bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+    bool EmitIdentifier(utils::StringStream& out, const ast::IdentifierExpression* expr);
     /// Handles a member accessor expression
     /// @param out the output of the expression stream
     /// @param expr the member accessor expression
     /// @returns true if the member accessor was emitted
-    bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+    bool EmitMemberAccessor(utils::StringStream& out, const ast::MemberAccessorExpression* expr);
     /// Handles return statements
     /// @param stmt the statement to emit
     /// @returns true if the statement was successfully emitted
@@ -413,7 +418,7 @@
     /// @param name_printed (optional) if not nullptr and an array was printed
     /// then the boolean is set to true.
     /// @returns true if the type is emitted
-    bool EmitType(std::ostream& out,
+    bool EmitType(utils::StringStream& out,
                   const type::Type* type,
                   builtin::AddressSpace address_space,
                   builtin::Access access,
@@ -426,7 +431,7 @@
     /// @param access the access control type of the variable
     /// @param name the name to emit
     /// @returns true if the type is emitted
-    bool EmitTypeAndName(std::ostream& out,
+    bool EmitTypeAndName(utils::StringStream& out,
                          const type::Type* type,
                          builtin::AddressSpace address_space,
                          builtin::Access access,
@@ -446,12 +451,12 @@
     /// @param out the output of the expression stream
     /// @param expr the expression to emit
     /// @returns true if the expression was emitted
-    bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+    bool EmitUnaryOp(utils::StringStream& out, const ast::UnaryOpExpression* expr);
     /// Emits the zero value for the given type
     /// @param out the output stream
     /// @param type the type to emit the value for
     /// @returns true if the zero value was successfully emitted.
-    bool EmitZeroValue(std::ostream& out, const type::Type* type);
+    bool EmitZeroValue(utils::StringStream& out, const type::Type* type);
     /// Handles generating a 'var' declaration
     /// @param var the variable to generate
     /// @returns true if the variable was emitted
@@ -504,7 +509,7 @@
     ///          `params` is the name of all the generated function parameters
     /// @returns true if the call expression is emitted
     template <typename F>
-    bool CallBuiltinHelper(std::ostream& out,
+    bool CallBuiltinHelper(utils::StringStream& out,
                            const ast::CallExpression* call,
                            const sem::Builtin* builtin,
                            F&& build);
diff --git a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
index bd405d3..453af22 100644
--- a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
@@ -14,6 +14,8 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+#include "src/tint/utils/string_stream.h"
+
 using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::writer::glsl {
@@ -28,7 +30,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "ary[5]");
 }
diff --git a/src/tint/writer/glsl/generator_impl_binary_test.cc b/src/tint/writer/glsl/generator_impl_binary_test.cc
index f90a428..475ae46 100644
--- a/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -14,6 +14,7 @@
 
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -55,7 +56,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), params.result);
 }
@@ -83,7 +84,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), params.result);
 }
@@ -102,7 +103,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), params.result);
 }
@@ -126,7 +127,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), params.result);
 }
@@ -161,7 +162,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(a * 1.0f)");
 }
@@ -179,7 +180,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(a * 1.0hf)");
 }
@@ -195,7 +196,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(1.0f * a)");
 }
@@ -213,7 +214,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(1.0hf * a)");
 }
@@ -228,7 +229,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(mat * 1.0f)");
 }
@@ -245,7 +246,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(mat * 1.0hf)");
 }
@@ -260,7 +261,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(1.0f * mat)");
 }
@@ -277,7 +278,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(1.0hf * mat)");
 }
@@ -292,7 +293,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(mat * vec3(1.0f))");
 }
@@ -309,7 +310,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(mat * f16vec3(1.0hf))");
 }
@@ -324,7 +325,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(vec3(1.0f) * mat)");
 }
@@ -341,7 +342,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(f16vec3(1.0hf) * mat)");
 }
@@ -355,7 +356,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(lhs * rhs)");
 }
@@ -371,7 +372,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(lhs * rhs)");
 }
@@ -385,7 +386,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -401,7 +402,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -415,7 +416,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -431,7 +432,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -445,7 +446,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -461,7 +462,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -475,7 +476,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -491,7 +492,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
@@ -592,7 +593,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(tint_tmp)");
     EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
@@ -617,7 +618,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(tint_tmp)");
     EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
@@ -644,7 +645,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), "(tint_tmp)");
     EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
diff --git a/src/tint/writer/glsl/generator_impl_bitcast_test.cc b/src/tint/writer/glsl/generator_impl_bitcast_test.cc
index a7d2f66..b6e4f92 100644
--- a/src/tint/writer/glsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_bitcast_test.cc
@@ -14,6 +14,8 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+#include "src/tint/utils/string_stream.h"
+
 using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::writer::glsl {
@@ -28,7 +30,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
     EXPECT_EQ(out.str(), "intBitsToFloat(a)");
 }
@@ -40,7 +42,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
     EXPECT_EQ(out.str(), "int(a)");
 }
@@ -52,7 +54,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
     EXPECT_EQ(out.str(), "uint(a)");
 }
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index fa0781b..3d14a68 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -16,6 +16,7 @@
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/sem/call.h"
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 using ::testing::HasSubstr;
@@ -65,8 +66,8 @@
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
-    std::ostringstream str(name);
-    str << builtin;
+    utils::StringStream str;
+    str << name << builtin;
     switch (builtin) {
         case BuiltinType::kAcos:
         case BuiltinType::kAsin:
@@ -350,7 +351,7 @@
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "dot(param1, param2)");
 }
@@ -363,7 +364,7 @@
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "(true ? b : a)");
 }
@@ -376,7 +377,7 @@
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "mix(a, b, bvec2(true, false))");
 }
@@ -393,7 +394,7 @@
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "((a) * (b) + (c))");
 }
@@ -411,7 +412,7 @@
     GeneratorImpl& gen = Build();
 
     gen.increment_indent();
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "((a) * (b) + (c))");
 }
@@ -931,7 +932,7 @@
     EXPECT_EQ(gen.result(), R"(#version 310 es
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -959,7 +960,7 @@
     EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec3 tint_degrees(vec3 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -990,7 +991,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 float16_t tint_degrees(float16_t param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -1021,7 +1022,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec3 tint_degrees(f16vec3 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -1049,7 +1050,7 @@
     EXPECT_EQ(gen.result(), R"(#version 310 es
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -1077,7 +1078,7 @@
     EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec3 tint_radians(vec3 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -1108,7 +1109,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 float16_t tint_radians(float16_t param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -1139,7 +1140,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec3 tint_radians(f16vec3 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
diff --git a/src/tint/writer/glsl/generator_impl_call_test.cc b/src/tint/writer/glsl/generator_impl_call_test.cc
index 2f81463..69a78f4 100644
--- a/src/tint/writer/glsl/generator_impl_call_test.cc
+++ b/src/tint/writer/glsl/generator_impl_call_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/ast/call_statement.h"
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -30,7 +31,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "my_func()");
 }
@@ -50,7 +51,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
     EXPECT_EQ(out.str(), "my_func(param1, param2)");
 }
diff --git a/src/tint/writer/glsl/generator_impl_cast_test.cc b/src/tint/writer/glsl/generator_impl_cast_test.cc
index 4954dee..41ee6f0 100644
--- a/src/tint/writer/glsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_cast_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -27,7 +28,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
     EXPECT_EQ(out.str(), "1.0f");
 }
@@ -38,7 +39,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
     EXPECT_EQ(out.str(), "vec3(1.0f, 2.0f, 3.0f)");
 }
diff --git a/src/tint/writer/glsl/generator_impl_identifier_test.cc b/src/tint/writer/glsl/generator_impl_identifier_test.cc
index cd0b109..64b9fb3 100644
--- a/src/tint/writer/glsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/glsl/generator_impl_identifier_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 namespace tint::writer::glsl {
@@ -27,7 +28,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
     EXPECT_EQ(out.str(), "foo");
 }
diff --git a/src/tint/writer/glsl/generator_impl_import_test.cc b/src/tint/writer/glsl/generator_impl_import_test.cc
index 10da8aa..3201712 100644
--- a/src/tint/writer/glsl/generator_impl_import_test.cc
+++ b/src/tint/writer/glsl/generator_impl_import_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -39,7 +40,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f)");
 }
@@ -78,7 +79,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1)");
 }
@@ -95,7 +96,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(),
               std::string(param.glsl_name) + "(vec3(0.100000001f, 0.200000003f, 0.300000012f))");
@@ -136,7 +137,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f)");
 }
@@ -158,7 +159,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(),
               std::string(param.glsl_name) + "(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f))");
@@ -183,7 +184,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2)");
 }
@@ -201,7 +202,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f, 3.0f)");
 }
@@ -221,7 +222,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(),
               std::string(param.glsl_name) +
@@ -242,7 +243,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2, 3)");
 }
@@ -258,7 +259,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
     EXPECT_EQ(out.str(), std::string("determinant(var)"));
 }
diff --git a/src/tint/writer/glsl/generator_impl_type_test.cc b/src/tint/writer/glsl/generator_impl_type_test.cc
index 492910d..2cc13f6 100644
--- a/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -21,6 +21,7 @@
 #include "src/tint/type/sampler.h"
 #include "src/tint/type/storage_texture.h"
 #include "src/tint/type/texture_dimension.h"
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 using ::testing::HasSubstr;
@@ -38,7 +39,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, "ary"))
         << gen.error();
@@ -51,7 +52,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, "ary"))
         << gen.error();
@@ -64,7 +65,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, "ary"))
         << gen.error();
@@ -77,7 +78,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, program->TypeOf(ty), builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -89,7 +90,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, bool_, builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -101,7 +102,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, f32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -115,7 +116,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, f16, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -127,7 +128,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, i32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -141,7 +142,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -157,7 +158,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, mat2x3, builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -194,7 +195,7 @@
     GeneratorImpl& gen = Build();
 
     auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, sem_s, builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -243,7 +244,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, u32, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -256,7 +257,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -271,7 +272,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, vec3, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -283,7 +284,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitType(out, void_, builtin::AddressSpace::kUndefined,
                              builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -295,7 +296,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_FALSE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
                               builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -306,7 +307,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_FALSE(gen.EmitType(out, sampler, builtin::AddressSpace::kUndefined,
                               builtin::Access::kReadWrite, ""))
         << gen.error();
@@ -513,7 +514,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(
         gen.EmitType(out, s, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite, ""))
         << gen.error();
diff --git a/src/tint/writer/glsl/generator_impl_unary_op_test.cc b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
index 18f180e..b7c5fd1 100644
--- a/src/tint/writer/glsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 namespace tint::writer::glsl {
@@ -26,7 +27,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
     EXPECT_EQ(out.str(), "expr");
 }
@@ -38,7 +39,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
     EXPECT_EQ(out.str(), "~(expr)");
 }
@@ -51,7 +52,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
     EXPECT_EQ(out.str(), "expr");
 }
@@ -63,7 +64,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
     EXPECT_EQ(out.str(), "!(expr)");
 }
@@ -75,7 +76,7 @@
 
     GeneratorImpl& gen = Build();
 
-    std::stringstream out;
+    utils::StringStream out;
     ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
     EXPECT_EQ(out.str(), "-(expr)");
 }
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index 7cd3de3..3dbbe7d 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -811,7 +811,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 [numthreads(1, 1, 1)]
@@ -832,7 +832,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(float3 tint_degrees(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 [numthreads(1, 1, 1)]
@@ -855,7 +855,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(float16_t tint_degrees(float16_t param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 [numthreads(1, 1, 1)]
@@ -878,7 +878,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> tint_degrees(vector<float16_t, 3> param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 [numthreads(1, 1, 1)]
@@ -899,7 +899,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 [numthreads(1, 1, 1)]
@@ -920,7 +920,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(float3 tint_radians(float3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 [numthreads(1, 1, 1)]
@@ -943,7 +943,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(float16_t tint_radians(float16_t param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 [numthreads(1, 1, 1)]
@@ -966,7 +966,7 @@
 
     ASSERT_TRUE(gen.Generate()) << gen.error();
     EXPECT_EQ(gen.result(), R"(vector<float16_t, 3> tint_radians(vector<float16_t, 3> param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 [numthreads(1, 1, 1)]
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index 84fb7d5..4b24e33 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -850,7 +850,7 @@
 using namespace metal;
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 kernel void test_function() {
@@ -875,7 +875,7 @@
 using namespace metal;
 
 float3 tint_degrees(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 kernel void test_function() {
@@ -902,7 +902,7 @@
 using namespace metal;
 
 half tint_degrees(half param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 kernel void test_function() {
@@ -929,7 +929,7 @@
 using namespace metal;
 
 half3 tint_degrees(half3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 kernel void test_function() {
@@ -954,7 +954,7 @@
 using namespace metal;
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 kernel void test_function() {
@@ -979,7 +979,7 @@
 using namespace metal;
 
 float3 tint_radians(float3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 kernel void test_function() {
@@ -1006,7 +1006,7 @@
 using namespace metal;
 
 half tint_radians(half param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 kernel void test_function() {
@@ -1033,7 +1033,7 @@
 using namespace metal;
 
 half3 tint_radians(half3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 kernel void test_function() {
diff --git a/src/tint/writer/text_generator.cc b/src/tint/writer/text_generator.cc
index 6d29844..7534835 100644
--- a/src/tint/writer/text_generator.cc
+++ b/src/tint/writer/text_generator.cc
@@ -130,6 +130,7 @@
 TextGenerator::ScopedParen::ScopedParen(std::ostream& stream) : s(stream) {
     s << "(";
 }
+
 TextGenerator::ScopedParen::~ScopedParen() {
     s << ")";
 }
diff --git a/src/tint/writer/text_generator.h b/src/tint/writer/text_generator.h
index 1c22522..b53aef0 100644
--- a/src/tint/writer/text_generator.h
+++ b/src/tint/writer/text_generator.h
@@ -23,6 +23,7 @@
 
 #include "src/tint/diagnostic/diagnostic.h"
 #include "src/tint/program_builder.h"
+#include "src/tint/utils/string_stream.h"
 
 namespace tint::writer {
 
@@ -139,13 +140,16 @@
         /// Destructor
         ~LineWriter();
 
-        /// @returns the ostringstream
-        operator std::ostream&() { return os; }
+        /// [DEPRECATED] Remove when utils::StringStream conversion is done
+        /// @returns the utils::StringStream
+        operator std::ostream&() { return os.stream(); }
+        /// @returns the utils::StringStream
+        operator utils::StringStream&() { return os; }
 
         /// @param rhs the value to write to the line
-        /// @returns the ostream so calls can be chained
+        /// @returns the utils::StringStream so calls can be chained
         template <typename T>
-        std::ostream& operator<<(T&& rhs) {
+        utils::StringStream& operator<<(T&& rhs) {
             return os << std::forward<T>(rhs);
         }
 
@@ -153,13 +157,14 @@
         LineWriter(const LineWriter&) = delete;
         LineWriter& operator=(const LineWriter&) = delete;
 
-        std::ostringstream os;
+        utils::StringStream os;
         TextBuffer* buffer;
     };
 
     /// Helper for writing a '(' on construction and a ')' destruction.
     struct ScopedParen {
         /// Constructor
+        /// [DEPRECATED] This should be utils::StringStream when conversion is done
         /// @param stream the std::ostream that will be written to
         explicit ScopedParen(std::ostream& stream);
         /// Destructor
diff --git a/test/tint/builtins/degrees.spvasm.expected.dxc.hlsl b/test/tint/builtins/degrees.spvasm.expected.dxc.hlsl
index ca48301..6baebf9 100644
--- a/test/tint/builtins/degrees.spvasm.expected.dxc.hlsl
+++ b/test/tint/builtins/degrees.spvasm.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void main_1() {
diff --git a/test/tint/builtins/degrees.spvasm.expected.fxc.hlsl b/test/tint/builtins/degrees.spvasm.expected.fxc.hlsl
index ca48301..6baebf9 100644
--- a/test/tint/builtins/degrees.spvasm.expected.fxc.hlsl
+++ b/test/tint/builtins/degrees.spvasm.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void main_1() {
diff --git a/test/tint/builtins/degrees.spvasm.expected.glsl b/test/tint/builtins/degrees.spvasm.expected.glsl
index 59705a2..bc50976 100644
--- a/test/tint/builtins/degrees.spvasm.expected.glsl
+++ b/test/tint/builtins/degrees.spvasm.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
diff --git a/test/tint/builtins/degrees.spvasm.expected.msl b/test/tint/builtins/degrees.spvasm.expected.msl
index cb9ce57..d5dca09 100644
--- a/test/tint/builtins/degrees.spvasm.expected.msl
+++ b/test/tint/builtins/degrees.spvasm.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void main_1() {
diff --git a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.dxc.hlsl
index 2f7e58a..a434094 100644
--- a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float4 tint_degrees(float4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_0d170c() {
diff --git a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.fxc.hlsl
index 2f7e58a..a434094 100644
--- a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float4 tint_degrees(float4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_0d170c() {
diff --git a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.glsl
index 44c9a1a..eaf2c76 100644
--- a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 vec4 tint_degrees(vec4 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 vec4 tint_degrees(vec4 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 vec4 tint_degrees(vec4 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.msl
index d1297cc..a43d3dd 100644
--- a/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/0d170c.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float4 tint_degrees(float4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_0d170c() {
diff --git a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.dxc.hlsl
index ff76e46..d4345b0 100644
--- a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float2 tint_degrees(float2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_1ad5df() {
diff --git a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.fxc.hlsl
index ff76e46..d4345b0 100644
--- a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float2 tint_degrees(float2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_1ad5df() {
diff --git a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.glsl
index e3e890f..d4a56ed 100644
--- a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 vec2 tint_degrees(vec2 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 vec2 tint_degrees(vec2 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 vec2 tint_degrees(vec2 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.msl
index 8c258eb..22bdbb2 100644
--- a/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/1ad5df.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float2 tint_degrees(float2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_1ad5df() {
diff --git a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.dxc.hlsl
index b16be3d..c32b82b 100644
--- a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float3 tint_degrees(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_2af623() {
diff --git a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.fxc.hlsl
index b16be3d..c32b82b 100644
--- a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float3 tint_degrees(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_2af623() {
diff --git a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.glsl
index fa113c8..41f8cc4 100644
--- a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 vec3 tint_degrees(vec3 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 vec3 tint_degrees(vec3 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 vec3 tint_degrees(vec3 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.msl
index 46aaa0b..befd29a 100644
--- a/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/2af623.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float3 tint_degrees(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_2af623() {
diff --git a/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.dxc.hlsl
index e2b7da8..5fddbd7 100644
--- a/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 vector<float16_t, 4> tint_degrees(vector<float16_t, 4> param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_3055d3() {
diff --git a/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.glsl
index 0b4d067..9268aac 100644
--- a/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec4 tint_degrees(f16vec4 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 f16vec4 tint_degrees(f16vec4 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec4 tint_degrees(f16vec4 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.msl
index a14dbf8..c1f4067 100644
--- a/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/3055d3.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half4 tint_degrees(half4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_3055d3() {
diff --git a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.dxc.hlsl
index 9821514..7482ab6 100644
--- a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_51f705() {
diff --git a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.fxc.hlsl
index 9821514..7482ab6 100644
--- a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_51f705() {
diff --git a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.glsl
index 78500d7..26c1436 100644
--- a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.msl
index 4feaad0..c46fd92 100644
--- a/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/51f705.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float tint_degrees(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_51f705() {
diff --git a/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.dxc.hlsl
index 3616145..650bf8d 100644
--- a/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float16_t tint_degrees(float16_t param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_5e9805() {
diff --git a/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.glsl
index 5f997f2..1eded00 100644
--- a/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 float16_t tint_degrees(float16_t param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 float16_t tint_degrees(float16_t param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 float16_t tint_degrees(float16_t param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.msl
index a3fde5c..ddee167 100644
--- a/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/5e9805.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half tint_degrees(half param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_5e9805() {
diff --git a/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.dxc.hlsl
index 2e9d203..3d9d88c 100644
--- a/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 vector<float16_t, 3> tint_degrees(vector<float16_t, 3> param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_dfe8f4() {
diff --git a/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.glsl
index df614921..b4de681 100644
--- a/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec3 tint_degrees(f16vec3 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 f16vec3 tint_degrees(f16vec3 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec3 tint_degrees(f16vec3 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.msl
index c9135cd..d226ae3 100644
--- a/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/dfe8f4.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half3 tint_degrees(half3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_dfe8f4() {
diff --git a/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.dxc.hlsl
index 1936b6a..5107ffa 100644
--- a/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 vector<float16_t, 2> tint_degrees(vector<float16_t, 2> param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_f59715() {
diff --git a/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.glsl b/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.glsl
index d4665f0..9af36b8 100644
--- a/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec2 tint_degrees(f16vec2 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 f16vec2 tint_degrees(f16vec2 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec2 tint_degrees(f16vec2 param_0) {
-  return param_0 * 57.295779513082322865hf;
+  return param_0 * 57.295779513082323hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.msl b/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.msl
index 5a10bbf..02992fc 100644
--- a/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/degrees/f59715.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half2 tint_degrees(half2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 void degrees_f59715() {
diff --git a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.dxc.hlsl
index 53dad5b..b369725 100644
--- a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float4 tint_radians(float4 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_09b7fc() {
diff --git a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.fxc.hlsl
index 53dad5b..b369725 100644
--- a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float4 tint_radians(float4 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_09b7fc() {
diff --git a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.glsl
index 1ff16ba..e5a3c60 100644
--- a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 vec4 tint_radians(vec4 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 vec4 tint_radians(vec4 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 vec4 tint_radians(vec4 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.msl
index eabe094..b841867 100644
--- a/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/09b7fc.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float4 tint_radians(float4 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_09b7fc() {
diff --git a/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.dxc.hlsl
index 62ae57a..c4c934c 100644
--- a/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float16_t tint_radians(float16_t param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_208fd9() {
diff --git a/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.glsl
index ad613e2..35dfd17 100644
--- a/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 float16_t tint_radians(float16_t param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 float16_t tint_radians(float16_t param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 float16_t tint_radians(float16_t param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.msl
index 7684ab3..ede8949 100644
--- a/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/208fd9.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half tint_radians(half param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_208fd9() {
diff --git a/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.dxc.hlsl
index 10ccec1..e3dff23 100644
--- a/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 vector<float16_t, 4> tint_radians(vector<float16_t, 4> param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_44f20b() {
diff --git a/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.glsl
index 74c7c9e..a9de4a8 100644
--- a/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec4 tint_radians(f16vec4 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 f16vec4 tint_radians(f16vec4 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec4 tint_radians(f16vec4 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.msl
index 058c38e..565d93c 100644
--- a/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/44f20b.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half4 tint_radians(half4 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_44f20b() {
diff --git a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.dxc.hlsl
index 690db4d..b76179f 100644
--- a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float2 tint_radians(float2 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_61687a() {
diff --git a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.fxc.hlsl
index 690db4d..b76179f 100644
--- a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float2 tint_radians(float2 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_61687a() {
diff --git a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.glsl
index acf786c..c1bef7a 100644
--- a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 vec2 tint_radians(vec2 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 vec2 tint_radians(vec2 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 vec2 tint_radians(vec2 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.msl
index 995b3cf..e9de7f1 100644
--- a/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/61687a.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float2 tint_radians(float2 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_61687a() {
diff --git a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.dxc.hlsl
index e10a17d..8385da9 100644
--- a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_6b0ff2() {
diff --git a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.fxc.hlsl
index e10a17d..8385da9 100644
--- a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_6b0ff2() {
diff --git a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.glsl
index 2a2bcd2..d51bdf3 100644
--- a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.msl
index 8a969a7..43391ed 100644
--- a/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/6b0ff2.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_6b0ff2() {
diff --git a/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.dxc.hlsl
index f2a40ae..84a7b19 100644
--- a/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 vector<float16_t, 3> tint_radians(vector<float16_t, 3> param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_7ea4c7() {
diff --git a/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.glsl
index 4faaa11..5524a7d 100644
--- a/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec3 tint_radians(f16vec3 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 f16vec3 tint_radians(f16vec3 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec3 tint_radians(f16vec3 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.msl
index 08af0d8..e6ebb854 100644
--- a/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/7ea4c7.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half3 tint_radians(half3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_7ea4c7() {
diff --git a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.dxc.hlsl
index d67bb7d..386bc10 100644
--- a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float3 tint_radians(float3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_f96258() {
diff --git a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.fxc.hlsl b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.fxc.hlsl
index d67bb7d..386bc10 100644
--- a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float3 tint_radians(float3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_f96258() {
diff --git a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.glsl
index 79eb5ec..02c349a 100644
--- a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 vec3 tint_radians(vec3 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -27,7 +27,7 @@
 precision mediump float;
 
 vec3 tint_radians(vec3 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
@@ -47,7 +47,7 @@
 #version 310 es
 
 vec3 tint_radians(vec3 param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.msl
index 1eabde2..3b7652a 100644
--- a/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/f96258.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float3 tint_radians(float3 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_f96258() {
diff --git a/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.dxc.hlsl b/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.dxc.hlsl
index 02162ec..f0c7eeb 100644
--- a/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 vector<float16_t, 2> tint_radians(vector<float16_t, 2> param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_fbacf0() {
diff --git a/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.glsl b/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.glsl
index 47b268d..fe5da30 100644
--- a/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.glsl
+++ b/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.glsl
@@ -2,7 +2,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec2 tint_radians(f16vec2 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -29,7 +29,7 @@
 precision mediump float;
 
 f16vec2 tint_radians(f16vec2 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
@@ -50,7 +50,7 @@
 #extension GL_AMD_gpu_shader_half_float : require
 
 f16vec2 tint_radians(f16vec2 param_0) {
-  return param_0 * 0.017453292519943295474hf;
+  return param_0 * 0.017453292519943295hf;
 }
 
 
diff --git a/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.msl b/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.msl
index 65e09d5..533774b 100644
--- a/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.msl
+++ b/test/tint/builtins/gen/var/radians/fbacf0.wgsl.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 half2 tint_radians(half2 param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void radians_fbacf0() {
diff --git a/test/tint/builtins/radians.spvasm.expected.dxc.hlsl b/test/tint/builtins/radians.spvasm.expected.dxc.hlsl
index 26b810c..2303412 100644
--- a/test/tint/builtins/radians.spvasm.expected.dxc.hlsl
+++ b/test/tint/builtins/radians.spvasm.expected.dxc.hlsl
@@ -1,5 +1,5 @@
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void main_1() {
diff --git a/test/tint/builtins/radians.spvasm.expected.fxc.hlsl b/test/tint/builtins/radians.spvasm.expected.fxc.hlsl
index 26b810c..2303412 100644
--- a/test/tint/builtins/radians.spvasm.expected.fxc.hlsl
+++ b/test/tint/builtins/radians.spvasm.expected.fxc.hlsl
@@ -1,5 +1,5 @@
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void main_1() {
diff --git a/test/tint/builtins/radians.spvasm.expected.glsl b/test/tint/builtins/radians.spvasm.expected.glsl
index 4475334..9081931 100644
--- a/test/tint/builtins/radians.spvasm.expected.glsl
+++ b/test/tint/builtins/radians.spvasm.expected.glsl
@@ -1,7 +1,7 @@
 #version 310 es
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474f;
+  return param_0 * 0.017453292519943295f;
 }
 
 
diff --git a/test/tint/builtins/radians.spvasm.expected.msl b/test/tint/builtins/radians.spvasm.expected.msl
index ce9422e..fa65e53 100644
--- a/test/tint/builtins/radians.spvasm.expected.msl
+++ b/test/tint/builtins/radians.spvasm.expected.msl
@@ -3,7 +3,7 @@
 using namespace metal;
 
 float tint_radians(float param_0) {
-  return param_0 * 0.017453292519943295474;
+  return param_0 * 0.017453292519943295;
 }
 
 void main_1() {
diff --git a/test/tint/builtins/repeated_use.wgsl.expected.dxc.hlsl b/test/tint/builtins/repeated_use.wgsl.expected.dxc.hlsl
index 5d53231..f17d098 100644
--- a/test/tint/builtins/repeated_use.wgsl.expected.dxc.hlsl
+++ b/test/tint/builtins/repeated_use.wgsl.expected.dxc.hlsl
@@ -1,17 +1,17 @@
 float4 tint_degrees(float4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float3 tint_degrees_1(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float2 tint_degrees_2(float2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float tint_degrees_3(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/builtins/repeated_use.wgsl.expected.fxc.hlsl b/test/tint/builtins/repeated_use.wgsl.expected.fxc.hlsl
index 5d53231..f17d098 100644
--- a/test/tint/builtins/repeated_use.wgsl.expected.fxc.hlsl
+++ b/test/tint/builtins/repeated_use.wgsl.expected.fxc.hlsl
@@ -1,17 +1,17 @@
 float4 tint_degrees(float4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float3 tint_degrees_1(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float2 tint_degrees_2(float2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float tint_degrees_3(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 [numthreads(1, 1, 1)]
diff --git a/test/tint/builtins/repeated_use.wgsl.expected.glsl b/test/tint/builtins/repeated_use.wgsl.expected.glsl
index c40ba04..bcb62f2 100644
--- a/test/tint/builtins/repeated_use.wgsl.expected.glsl
+++ b/test/tint/builtins/repeated_use.wgsl.expected.glsl
@@ -1,19 +1,19 @@
 #version 310 es
 
 vec4 tint_degrees(vec4 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 vec3 tint_degrees_1(vec3 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 vec2 tint_degrees_2(vec2 param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 float tint_degrees_3(float param_0) {
-  return param_0 * 57.295779513082322865f;
+  return param_0 * 57.295779513082323f;
 }
 
 
diff --git a/test/tint/builtins/repeated_use.wgsl.expected.msl b/test/tint/builtins/repeated_use.wgsl.expected.msl
index 03ffb6a..34f83f3 100644
--- a/test/tint/builtins/repeated_use.wgsl.expected.msl
+++ b/test/tint/builtins/repeated_use.wgsl.expected.msl
@@ -3,19 +3,19 @@
 using namespace metal;
 
 float4 tint_degrees(float4 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float3 tint_degrees_1(float3 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float2 tint_degrees_2(float2 param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 float tint_degrees_3(float param_0) {
-  return param_0 * 57.295779513082322865;
+  return param_0 * 57.295779513082323;
 }
 
 kernel void tint_symbol() {