diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index 51341d96e4..ab74470ac6 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -283,61 +283,61 @@ void json_lexer_init(JSONLexer *lexer, bool enable_interpolation)
 static void json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
 {
     int new_state;
     bool char_consumed = false;
 
     lexer->x++;
     if (ch == '\n') {
         lexer->x = 0;
         lexer->y++;
     }
 
     while (flush ? lexer->state != lexer->start_state : !char_consumed) {
         new_state = next_state(lexer, ch, flush, &char_consumed);
         if (char_consumed) {
             assert(!flush);
             g_string_append_c(lexer->token, ch);
         }
 
         switch (new_state) {
         case JSON_LCURLY:
         case JSON_RCURLY:
         case JSON_LSQUARE:
         case JSON_RSQUARE:
         case JSON_COLON:
         case JSON_COMMA:
         case JSON_INTERP:
         case JSON_INTEGER:
         case JSON_FLOAT:
         case JSON_KEYWORD:
         case JSON_STRING:
             json_message_process_token(lexer, lexer->token, new_state,
                                        lexer->x, lexer->y);
-            /* fall through */
+            fallthrough;
         case IN_START:
             g_string_truncate(lexer->token, 0);
             new_state = lexer->start_state;
             break;
         case JSON_ERROR:
             json_message_process_token(lexer, lexer->token, JSON_ERROR,
                                        lexer->x, lexer->y);
             new_state = IN_RECOVERY;
-            /* fall through */
+            fallthrough;
         case IN_RECOVERY:
             g_string_truncate(lexer->token, 0);
             break;
         default:
             break;
         }
         lexer->state = new_state;
     }
 
     /* Do not let a single token grow to an arbitrarily large size,
      * this is a security consideration.
      */
     if (lexer->token->len > MAX_TOKEN_SIZE) {
         json_message_process_token(lexer, lexer->token, lexer->state,
                                    lexer->x, lexer->y);
         g_string_truncate(lexer->token, 0);
         lexer->state = lexer->start_state;
     }
 }
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index d498db6e70..4dc622dcc9 100644
--- a/qobject/json-parser.c
+++ b/qobject/json-parser.c
@@ -95,137 +95,137 @@ static int cvt4hex(const char *s)
 /**
  * parse_string(): Parse a JSON string
  *
  * From RFC 8259 "The JavaScript Object Notation (JSON) Data
  * Interchange Format":
  *
  *    char = unescaped /
  *        escape (
  *            %x22 /          ; "    quotation mark  U+0022
  *            %x5C /          ; \    reverse solidus U+005C
  *            %x2F /          ; /    solidus         U+002F
  *            %x62 /          ; b    backspace       U+0008
  *            %x66 /          ; f    form feed       U+000C
  *            %x6E /          ; n    line feed       U+000A
  *            %x72 /          ; r    carriage return U+000D
  *            %x74 /          ; t    tab             U+0009
  *            %x75 4HEXDIG )  ; uXXXX                U+XXXX
  *    escape = %x5C              ; \
  *    quotation-mark = %x22      ; "
  *    unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
  *
  * Extensions over RFC 8259:
  * - Extra escape sequence in strings:
  *   0x27 (apostrophe) is recognized after escape, too
  * - Single-quoted strings:
  *   Like double-quoted strings, except they're delimited by %x27
  *   (apostrophe) instead of %x22 (quotation mark), and can't contain
  *   unescaped apostrophe, but can contain unescaped quotation mark.
  *
  * Note:
  * - Encoding is modified UTF-8.
  * - Invalid Unicode characters are rejected.
  * - Control characters \x00..\x1F are rejected by the lexer.
  */
 static QString *parse_string(JSONParserContext *ctxt, JSONToken *token)
 {
     const char *ptr = token->str;
     GString *str;
     char quote;
     const char *beg;
     int cp, trailing;
     char *end;
     ssize_t len;
     char utf8_buf[5];
 
     assert(*ptr == '"' || *ptr == '\'');
     quote = *ptr++;
     str = g_string_new(NULL);
 
     while (*ptr != quote) {
         assert(*ptr);
         switch (*ptr) {
         case '\\':
             beg = ptr++;
             switch (*ptr++) {
             case '"':
                 g_string_append_c(str, '"');
                 break;
             case '\'':
                 g_string_append_c(str, '\'');
                 break;
             case '\\':
                 g_string_append_c(str, '\\');
                 break;
             case '/':
                 g_string_append_c(str, '/');
                 break;
             case 'b':
                 g_string_append_c(str, '\b');
                 break;
             case 'f':
                 g_string_append_c(str, '\f');
                 break;
             case 'n':
                 g_string_append_c(str, '\n');
                 break;
             case 'r':
                 g_string_append_c(str, '\r');
                 break;
             case 't':
                 g_string_append_c(str, '\t');
                 break;
             case 'u':
                 cp = cvt4hex(ptr);
                 ptr += 4;
 
                 /* handle surrogate pairs */
                 if (cp >= 0xD800 && cp <= 0xDBFF
                     && ptr[0] == '\\' && ptr[1] == 'u') {
                     /* leading surrogate followed by \u */
                     cp = 0x10000 + ((cp & 0x3FF) << 10);
                     trailing = cvt4hex(ptr + 2);
                     if (trailing >= 0xDC00 && trailing <= 0xDFFF) {
                         /* followed by trailing surrogate */
                         cp |= trailing & 0x3FF;
                         ptr += 6;
                     } else {
                         cp = -1; /* invalid */
                     }
                 }
 
                 if (mod_utf8_encode(utf8_buf, sizeof(utf8_buf), cp) < 0) {
                     parse_error(ctxt, token,
                                 "%.*s is not a valid Unicode character",
                                 (int)(ptr - beg), beg);
                     goto out;
                 }
                 g_string_append(str, utf8_buf);
                 break;
             default:
                 parse_error(ctxt, token, "invalid escape sequence in string");
                 goto out;
             }
             break;
         case '%':
             if (ctxt->ap) {
                 if (ptr[1] != '%') {
                     parse_error(ctxt, token, "can't interpolate into string");
                     goto out;
                 }
                 ptr++;
             }
-            /* fall through */
+            fallthrough;
         default:
             cp = mod_utf8_codepoint(ptr, 6, &end);
             if (cp < 0) {
                 parse_error(ctxt, token, "invalid UTF-8 sequence in string");
                 goto out;
             }
             ptr = end;
             len = mod_utf8_encode(utf8_buf, sizeof(utf8_buf), cp);
             assert(len >= 0);
             g_string_append(str, utf8_buf);
         }
     }
 
     return qstring_from_gstring(str);
@@ -481,51 +481,52 @@ static QObject *parse_interpolation(JSONParserContext *ctxt)
 static QObject *parse_literal(JSONParserContext *ctxt)
 {
     JSONToken *token;
 
     token = parser_context_pop_token(ctxt);
     assert(token);
 
     switch (token->type) {
     case JSON_STRING:
         return QOBJECT(parse_string(ctxt, token));
     case JSON_INTEGER: {
         /*
          * Represent JSON_INTEGER as QNUM_I64 if possible, else as
          * QNUM_U64, else as QNUM_DOUBLE.  Note that qemu_strtoi64()
          * and qemu_strtou64() fail with ERANGE when it's not
          * possible.
          *
          * qnum_get_int() will then work for any signed 64-bit
          * JSON_INTEGER, qnum_get_uint() for any unsigned 64-bit
          * integer, and qnum_get_double() both for any JSON_INTEGER
          * and any JSON_FLOAT (with precision loss for integers beyond
          * 53 bits)
          */
         int ret;
         int64_t value;
         uint64_t uvalue;
 
         ret = qemu_strtoi64(token->str, NULL, 10, &value);
         if (!ret) {
             return QOBJECT(qnum_from_int(value));
         }
         assert(ret == -ERANGE);
 
         if (token->str[0] != '-') {
             ret = qemu_strtou64(token->str, NULL, 10, &uvalue);
             if (!ret) {
                 return QOBJECT(qnum_from_uint(uvalue));
             }
             assert(ret == -ERANGE);
         }
+        /* fall through to JSON_FLOAT */
+        fallthrough;
     }
-    /* fall through to JSON_FLOAT */
     case JSON_FLOAT:
         /* FIXME dependent on locale; a pervasive issue in QEMU */
         /* FIXME our lexer matches RFC 8259 in forbidding Inf or NaN,
          * but those might be useful extensions beyond JSON */
         return QOBJECT(qnum_from_double(strtod(token->str, NULL)));
     default:
         abort();
     }
 }
