SPV_FAILED_MATCH error mutes DiagnosticStream.
authorDavid Neto <dneto@google.com>
Wed, 14 Oct 2015 15:31:51 +0000 (11:31 -0400)
committerDavid Neto <dneto@google.com>
Mon, 26 Oct 2015 16:55:33 +0000 (12:55 -0400)
The DiagnosticStream will not emit the accumulated message
text if the error is SPV_FAILED_MATCH.

Change various interfaces to accept the intended error
code instead of a boolean "is_optional".  This allows
us to avoid repeating the following type of logic deep
inside helper methods:

  if (is_optional) return SPV_FAILED_MATCH;
  return diagnostic() << " message text ";

source/diagnostic.cpp
source/diagnostic.h
source/text.cpp
source/text_handler.cpp
source/text_handler.h
test/TextLiteral.cpp
test/TextToBinary.cpp

index 74ce76b..94f5799 100644 (file)
@@ -82,7 +82,7 @@ spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic) {
 
 
 DiagnosticStream::~DiagnosticStream() {
-  if (pDiagnostic_) {
+  if (pDiagnostic_ && error_ != SPV_FAILED_MATCH) {
     *pDiagnostic_ = spvDiagnosticCreate(position_, stream_.str().c_str());
   }
 }
index 27be491..d6c77fe 100644 (file)
@@ -54,7 +54,8 @@ class diagnostic_helper {
 
 // A DiagnosticStream remembers the current position of the input and an error
 // code, and captures diagnostic messages via the left-shift operator.
-// Captured messages are emitted during the destructor.
+// If the error code is not SPV_FAILED_MATCH, then captured messages are
+// emitted during the destructor.
 // TODO(awoloszyn): This is very similar to diagnostic_helper, and hides
 //                  the data more easily. Replace diagnostic_helper elsewhere
 //                  eventually.
index e2ccc3c..2bb0ba8 100644 (file)
@@ -172,7 +172,7 @@ spv_result_t encodeImmediate(libspirv::AssemblyContext* context,
   assert(*text == '!');
   uint32_t parse_result;
   if (auto error =
-          context->parseNumber(text + 1, false, &parse_result,
+          context->parseNumber(text + 1, SPV_ERROR_INVALID_TEXT, &parse_result,
                                "Invalid immediate integer: !"))
     return error;
   context->binaryEncodeU32(parse_result, pInst);
@@ -208,6 +208,12 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
     return SPV_SUCCESS;
   }
 
+  // Optional literal operands can fail to parse. In that case use
+  // SPV_FAILED_MATCH to avoid emitting a diagostic.  Use the following
+  // for those situations.
+  spv_result_t error_code_for_literals =
+      spvOperandIsOptional(type) ? SPV_FAILED_MATCH : SPV_ERROR_INVALID_TEXT;
+
   switch (type) {
     case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
     case SPV_OPERAND_TYPE_ID:
@@ -278,9 +284,9 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
       }
 
       if (auto error = context->binaryEncodeNumericLiteral(
-               textValue, spvOperandIsOptional(type), expected_type, pInst)) {
+              textValue, error_code_for_literals, expected_type, pInst)) {
         return error;
-     }
+      }
     } break;
     case SPV_OPERAND_TYPE_LITERAL_STRING:
     case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: {
@@ -288,12 +294,11 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
       spv_result_t error = spvTextToLiteral(textValue, &literal);
       if (error != SPV_SUCCESS) {
         if (error == SPV_ERROR_OUT_OF_MEMORY) return error;
-        if (spvOperandIsOptional(type)) return SPV_FAILED_MATCH;
-        return context->diagnostic() << "Invalid literal string '" << textValue
-                                     << "'.";
+        return context->diagnostic(error_code_for_literals)
+               << "Invalid literal string '" << textValue << "'.";
       }
       if (literal.type != SPV_LITERAL_TYPE_STRING) {
-        return context->diagnostic(SPV_FAILED_MATCH)
+        return context->diagnostic()
                << "Expected literal string, found literal number '" << textValue
                << "'.";
       }
index 39fe433..3b10582 100644 (file)
@@ -347,7 +347,7 @@ spv_result_t AssemblyContext::binaryEncodeU64(const uint64_t value,
 }
 
 spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
-    const char *val, bool is_optional, const IdType &type,
+    const char *val, spv_result_t error_code, const IdType &type,
     spv_instruction_t *pInst) {
   const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
   const bool is_floating = libspirv::isScalarFloating(type);
@@ -365,9 +365,9 @@ spv_result_t AssemblyContext::binaryEncodeNumericLiteral(
   // If we explicitly expect a floating-point number, we should handle that
   // first.
   if (is_floating || looks_like_float)
-    return binaryEncodeFloatingPointLiteral(val, is_optional, type, pInst);
+    return binaryEncodeFloatingPointLiteral(val, error_code, type, pInst);
 
-  return binaryEncodeIntegerLiteral(val, is_optional, type, pInst);
+  return binaryEncodeIntegerLiteral(val, error_code, type, pInst);
 }
 
 spv_result_t AssemblyContext::binaryEncodeString(
@@ -445,7 +445,7 @@ spv_result_t AssemblyContext::recordTypeIdForValue(uint32_t value,
 }
 
 spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
-    const char *val, bool is_optional, const IdType &type,
+    const char *val, spv_result_t error_code, const IdType &type,
     spv_instruction_t *pInst) {
   const auto bit_width = assumedBitWidth(type);
   switch (bit_width) {
@@ -454,14 +454,14 @@ spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
              << "Unsupported yet: 16-bit float constants.";
     case 32: {
       float fVal;
-      if (auto error = parseNumber(val, is_optional, &fVal,
+      if (auto error = parseNumber(val, error_code, &fVal,
                                    "Invalid 32-bit float literal: "))
         return error;
       return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
     } break;
     case 64: {
       double dVal;
-      if (auto error = parseNumber(val, is_optional, &dVal,
+      if (auto error = parseNumber(val, error_code, &dVal,
                                    "Invalid 64-bit float literal: "))
         return error;
       return binaryEncodeU64(BitwiseCast<uint64_t>(dVal), pInst);
@@ -473,7 +473,7 @@ spv_result_t AssemblyContext::binaryEncodeFloatingPointLiteral(
 }
 
 spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
-    const char *val, bool is_optional, const IdType &type,
+    const char *val, spv_result_t error_code, const IdType &type,
     spv_instruction_t *pInst) {
   const bool is_bottom = type.type_class == libspirv::IdTypeClass::kBottom;
   const auto bit_width = assumedBitWidth(type);
@@ -496,20 +496,20 @@ spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
   uint64_t decoded_bits;
   if (is_negative) {
     int64_t decoded_signed = 0;
-    if (auto error = parseNumber(val, is_optional, &decoded_signed,
+    if (auto error = parseNumber(val, error_code, &decoded_signed,
                                  "Invalid signed integer literal: "))
       return error;
     if (auto error = checkRangeAndIfHexThenSignExtend(
-            decoded_signed, is_optional, type, is_hex, &decoded_signed))
+            decoded_signed, error_code, type, is_hex, &decoded_signed))
       return error;
     decoded_bits = decoded_signed;
   } else {
     // There's no leading minus sign, so parse it as an unsigned integer.
-    if (auto error = parseNumber(val, is_optional, &decoded_bits,
+    if (auto error = parseNumber(val, error_code, &decoded_bits,
                                  "Invalid unsigned integer literal: "))
       return error;
     if (auto error = checkRangeAndIfHexThenSignExtend(
-            decoded_bits, is_optional, type, is_hex, &decoded_bits))
+            decoded_bits, error_code, type, is_hex, &decoded_bits))
       return error;
   }
   if (bit_width > 32) {
@@ -521,7 +521,7 @@ spv_result_t AssemblyContext::binaryEncodeIntegerLiteral(
 
 template <typename T>
 spv_result_t AssemblyContext::checkRangeAndIfHexThenSignExtend(
-    T value, bool is_optional, const IdType &type, bool is_hex,
+    T value, spv_result_t error_code, const IdType &type, bool is_hex,
     T *updated_value_for_hex) {
   // The encoded result has three regions of bits that are of interest, from
   // least to most significant:
@@ -569,12 +569,10 @@ spv_result_t AssemblyContext::checkRangeAndIfHexThenSignExtend(
   }
 
   if (failed) {
-    if (is_optional) return SPV_FAILED_MATCH;
-    return diagnostic() << "Integer " << (is_hex ? std::hex : std::dec)
-                        << std::showbase << value << " does not fit in a "
-                        << std::dec << bit_width << "-bit "
-                        << (type.isSigned ? "signed" : "unsigned")
-                        << " integer";
+    return diagnostic(error_code)
+           << "Integer " << (is_hex ? std::hex : std::dec) << std::showbase
+           << value << " does not fit in a " << std::dec << bit_width << "-bit "
+           << (type.isSigned ? "signed" : "unsigned") << " integer";
   }
 
   // Sign extend hex the number.
index 065a710..d2c0360 100644 (file)
@@ -238,9 +238,10 @@ class AssemblyContext {
   // If the type is of class kBottom the value will be encoded as a
   // 32-bit integer.
   // Returns SPV_SUCCESS if the value could be correctly added to the
-  // instruction.
+  // instruction.  Returns the given error code on failure, and emits
+  // a diagnotic if that error code is not SPV_FAILED_MATCH.
   spv_result_t binaryEncodeNumericLiteral(const char *numeric_literal,
-                                          bool optional,
+                                          spv_result_t error_code,
                                           const IdType &type,
                                           spv_instruction_t *pInst);
 
@@ -268,11 +269,11 @@ class AssemblyContext {
   // Parses a numeric value of a given type from the given text.  The number
   // should take up the entire string, and should be within bounds for the
   // target type.  On success, returns SPV_SUCCESS and populates the object
-  // referenced by value_pointer. On failure, returns SPV_FAILED_MATCH if
-  // is_optional is true, and returns SPV_ERROR_INVALID_TEXT and emits a
-  // diagnostic otherwise.
+  // referenced by value_pointer. On failure, returns the given error code,
+  // and emits a diagnostic if that error code is not SPV_FAILED_MATCH.
   template <typename T>
-  spv_result_t parseNumber(const char *text, bool is_optional, T *value_pointer,
+  spv_result_t parseNumber(const char *text, spv_result_t error_code,
+                           T *value_pointer,
                            const char *error_message_fragment) {
     // C++11 doesn't define std::istringstream(int8_t&), so calling this method
     // with a single-byte type leads to implementation-defined behaviour.
@@ -303,26 +304,27 @@ class AssemblyContext {
     }
 
     if (ok) return SPV_SUCCESS;
-    if (is_optional) return SPV_FAILED_MATCH;
-    return diagnostic() << error_message_fragment << text;
+    return diagnostic(error_code) << error_message_fragment << text;
   }
 
  private:
   // Appends the given floating point literal to the given instruction.
   // Returns SPV_SUCCESS if the value was correctly parsed.  Otherwise
-  // an error code is returned, and a message is emitted if is_optional
-  // is false.  Only 32 and 64 bit floating point numbers are supported.
+  // returns the given error code, and emits a diagnostic if that error
+  // code is not SPV_FAILED_MATCH.
+  // Only 32 and 64 bit floating point numbers are supported.
   spv_result_t binaryEncodeFloatingPointLiteral(const char *numeric_literal,
-                                                bool optional,
+                                                spv_result_t error_code,
                                                 const IdType& type,
                                                 spv_instruction_t *pInst);
 
   // Appends the given integer literal to the given instruction.
   // Returns SPV_SUCCESS if the value was correctly parsed.  Otherwise
-  // an error code is returned, and a message is emitted if is_optional
-  // is false.  Integers up to 64 bits are supported.
+  // returns the given error code, and emits a diagnostic if that error
+  // code is not SPV_FAILED_MATCH.
+  // Integers up to 64 bits are supported.
   spv_result_t binaryEncodeIntegerLiteral(const char *numeric_literal,
-                                          bool optional,
+                                          spv_result_t error_code,
                                           const IdType &type,
                                           spv_instruction_t *pInst);
 
@@ -332,10 +334,10 @@ class AssemblyContext {
   // the overflow bits should be zero.  If it was hex and the target type is
   // signed, then return the sign-extended value through the
   // updated_value_for_hex pointer argument.
-  // On failure, if is_optional is true then return SPV_FAILED_MATCH, otherwise
-  // emit a diagnostic and return SPV_ERROR_INVALID_TEXT.
+  // On failure, return the given error code and emit a diagnostic if that error
+  // code is not SPV_FAILED_MATCH.
   template <typename T>
-  spv_result_t checkRangeAndIfHexThenSignExtend(T value, bool is_optional,
+  spv_result_t checkRangeAndIfHexThenSignExtend(T value, spv_result_t error_code,
                                                 const IdType &type, bool is_hex,
                                                 T *updated_value_for_hex);
 
index 02b0d96..de328bc 100644 (file)
@@ -187,9 +187,10 @@ std::vector<uint32_t> successfulEncode(const TextLiteralCase& test,
       test.is_signed,
       type
   };
-  EXPECT_EQ(SPV_SUCCESS, libspirv::AssemblyContext(nullptr, &diagnostic)
-                             .binaryEncodeNumericLiteral(test.text, false,
-                                                         expected_type, &inst))
+ EXPECT_EQ(SPV_SUCCESS,
+            libspirv::AssemblyContext(nullptr, &diagnostic)
+                .binaryEncodeNumericLiteral(test.text, SPV_ERROR_INVALID_TEXT,
+                                            expected_type, &inst))
       << diagnostic->error;
   return inst.words;
 }
@@ -203,9 +204,10 @@ std::string failedEncode(const TextLiteralCase& test,
       test.is_signed,
       type
   };
-  EXPECT_NE(SPV_SUCCESS, libspirv::AssemblyContext(nullptr, &diagnostic)
-                             .binaryEncodeNumericLiteral(test.text, false,
-                                                         expected_type, &inst));
+  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
+            libspirv::AssemblyContext(nullptr, &diagnostic)
+                .binaryEncodeNumericLiteral(test.text, SPV_ERROR_INVALID_TEXT,
+                                            expected_type, &inst));
   std::string ret_val;
   if (diagnostic) {
     ret_val = diagnostic->error;
index 404b0a0..c8827aa 100644 (file)
@@ -452,153 +452,162 @@ INSTANTIATE_TEST_CASE_P(
 
 TEST(AssemblyContextParseNarrowSignedIntegers, Sample) {
   AssemblyContext context(AutoText(""), nullptr);
+  const spv_result_t ec = SPV_FAILED_MATCH;
   int16_t i16;
 
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", true, &i16, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", true, &i16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &i16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &i16, ""));
 
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", true, &i16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &i16, ""));
   EXPECT_EQ(0, i16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("32767", true, &i16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("32767", ec, &i16, ""));
   EXPECT_EQ(32767, i16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32768", true, &i16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32768", ec, &i16, ""));
   EXPECT_EQ(-32768, i16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", true, &i16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &i16, ""));
   EXPECT_EQ(0, i16);
 
   // These are out of range, so they should return an error.
   // The error code depends on whether this is an optional value.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("32768", true, &i16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("32768", ec, &i16, ""));
   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
-            context.parseNumber("65535", false, &i16, ""));
+            context.parseNumber("65535", SPV_ERROR_INVALID_TEXT, &i16, ""));
 
   // Check hex parsing.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0x7fff", true, &i16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0x7fff", ec, &i16, ""));
   EXPECT_EQ(32767, i16);
   // This is out of range.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0xffff", true, &i16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0xffff", ec, &i16, ""));
 }
 
 TEST(AssemblyContextParseNarrowUnsignedIntegers, Sample) {
   AssemblyContext context(AutoText(""), nullptr);
+  const spv_result_t ec = SPV_FAILED_MATCH;
   uint16_t u16;
 
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", true, &u16, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", true, &u16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &u16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &u16, ""));
 
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", true, &u16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &u16, ""));
   EXPECT_EQ(0, u16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("65535", true, &u16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("65535", ec, &u16, ""));
   EXPECT_EQ(65535, u16);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("65536", true, &u16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("65536", ec, &u16, ""));
 
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", true, &u16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &u16, ""));
   EXPECT_EQ(0, u16);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", true, &u16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", ec, &u16, ""));
   EXPECT_EQ(0, u16);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0xffff", true, &u16, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0xffff", ec, &u16, ""));
   EXPECT_EQ(0xffff, u16);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0x10000", true, &u16, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0x10000", ec, &u16, ""));
 }
 
 TEST(AssemblyContextParseWideSignedIntegers, Sample) {
   AssemblyContext context(AutoText(""), nullptr);
+  const spv_result_t ec = SPV_FAILED_MATCH;
   int64_t i64;
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", true, &i64, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", true, &i64, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", true, &i64, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &i64, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &i64, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &i64, ""));
   EXPECT_EQ(0, i64);
   EXPECT_EQ(SPV_SUCCESS,
-            context.parseNumber("0x7fffffffffffffff", true, &i64, ""));
+            context.parseNumber("0x7fffffffffffffff", ec, &i64, ""));
   EXPECT_EQ(0x7fffffffffffffff, i64);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", true, &i64, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &i64, ""));
   EXPECT_EQ(0, i64);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1", true, &i64, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1", ec, &i64, ""));
   EXPECT_EQ(-1, i64);
 }
 
 TEST(AssemblyContextParseWideUnsignedIntegers, Sample) {
   AssemblyContext context(AutoText(""), nullptr);
+  const spv_result_t ec = SPV_FAILED_MATCH;
   uint64_t u64;
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", true, &u64, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", true, &u64, ""));
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", true, &u64, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &u64, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &u64, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &u64, ""));
   EXPECT_EQ(0, u64);
   EXPECT_EQ(SPV_SUCCESS,
-            context.parseNumber("0xffffffffffffffff", true, &u64, ""));
+            context.parseNumber("0xffffffffffffffff", ec, &u64, ""));
   EXPECT_EQ(0xffffffffffffffffULL, u64);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", true, &u64, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-0", ec, &u64, ""));
   EXPECT_EQ(0, u64);
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", true, &u64, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1", ec, &u64, ""));
 }
 
 TEST(AssemblyContextParseFloat, Sample) {
   AssemblyContext context(AutoText(""), nullptr);
+  const spv_result_t ec = SPV_FAILED_MATCH;
   float f;
 
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", true, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", true, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &f, ""));
 
   // These values are exactly representatble.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &f, ""));
   EXPECT_EQ(0.0f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("42", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("42", ec, &f, ""));
   EXPECT_EQ(42.0f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2.5", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2.5", ec, &f, ""));
   EXPECT_EQ(2.5f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32.5", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32.5", ec, &f, ""));
   EXPECT_EQ(-32.5f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", ec, &f, ""));
   EXPECT_EQ(1e38f, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", ec, &f, ""));
   EXPECT_EQ(-1e38f, f);
 
   // Out of range.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e40", true, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e40", ec, &f, ""));
 }
 
 TEST(AssemblyContextParseDouble, Sample) {
   AssemblyContext context(AutoText(""), nullptr);
+  const spv_result_t ec = SPV_FAILED_MATCH;
   double f;
 
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", true, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", true, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("", ec, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("0=", ec, &f, ""));
 
   // These values are exactly representatble.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("0", ec, &f, ""));
   EXPECT_EQ(0.0, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("42", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("42", ec, &f, ""));
   EXPECT_EQ(42.0, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2.5", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("2.5", ec, &f, ""));
   EXPECT_EQ(2.5, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32.5", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-32.5", ec, &f, ""));
   EXPECT_EQ(-32.5, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e38", ec, &f, ""));
   EXPECT_EQ(1e38, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e38", ec, &f, ""));
   EXPECT_EQ(-1e38, f);
   // These are out of range for 32-bit float, but in range for 64-bit float.
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e40", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("1e40", ec, &f, ""));
   EXPECT_EQ(1e40, f);
-  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e40", true, &f, ""));
+  EXPECT_EQ(SPV_SUCCESS, context.parseNumber("-1e40", ec, &f, ""));
   EXPECT_EQ(-1e40, f);
 
   // Out of range.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e400", true, &f, ""));
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1e400", true, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("1e400", ec, &f, ""));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("-1e400", ec, &f, ""));
 }
 
 TEST(AssemblyContextParseMessages, Errors) {
   spv_diagnostic diag = nullptr;
+  const spv_result_t ec = SPV_FAILED_MATCH;
   AssemblyContext context(AutoText(""), &diag);
   int16_t i16;
 
   // No message is generated for a failure to parse an optional value.
-  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("abc", true, &i16, "bad narrow int: "));
+  EXPECT_EQ(SPV_FAILED_MATCH, context.parseNumber("abc", ec, &i16, "bad narrow int: "));
   EXPECT_EQ(nullptr, diag);
 
   // For a required value, use the message fragment.
-  EXPECT_EQ(SPV_ERROR_INVALID_TEXT, context.parseNumber("abc", false, &i16, "bad narrow int: "));
+  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
+            context.parseNumber("abc", SPV_ERROR_INVALID_TEXT, &i16,
+                                "bad narrow int: "));
   ASSERT_NE(nullptr, diag);
   EXPECT_EQ("bad narrow int: abc", std::string(diag->error));
   // Don't leak.