diff --git a/libc/fuzzing/stdio/CMakeLists.txt b/libc/fuzzing/stdio/CMakeLists.txt index bd7e38bc1401e..22de67d42747f 100644 --- a/libc/fuzzing/stdio/CMakeLists.txt +++ b/libc/fuzzing/stdio/CMakeLists.txt @@ -3,9 +3,7 @@ add_libc_fuzzer( SRCS printf_parser_fuzz.cpp DEPENDS - libc.src.stdio.printf_core.mock_parser - COMPILE_OPTIONS - -DLIBC_COPT_MOCK_ARG_LIST + libc.src.stdio.printf_core.parser ) add_libc_fuzzer( diff --git a/libc/fuzzing/stdio/printf_parser_fuzz.cpp b/libc/fuzzing/stdio/printf_parser_fuzz.cpp index 05cd616ca48b0..86f8c1e0a55f8 100644 --- a/libc/fuzzing/stdio/printf_parser_fuzz.cpp +++ b/libc/fuzzing/stdio/printf_parser_fuzz.cpp @@ -10,10 +10,6 @@ /// //===----------------------------------------------------------------------===// -#ifndef LIBC_COPT_MOCK_ARG_LIST -#error The printf Parser Fuzzer must be compiled with LIBC_COPT_MOCK_ARG_LIST, and the parser itself must also be compiled with that option when it's linked against the fuzzer. -#endif - #include "src/__support/arg_list.h" #include "src/stdio/printf_core/parser.h" @@ -37,7 +33,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { auto mock_arg_list = internal::MockArgList(); - auto parser = printf_core::Parser(in_str, mock_arg_list); + auto parser = + printf_core::Parser(in_str, mock_arg_list); int str_percent_count = 0; diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index 7087d28ede66e..c1a4b8cda85c9 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -8,28 +8,8 @@ add_header_library( libc.src.__support.FPUtil.fp_bits ) -add_object_library( +add_header_library( parser - SRCS - parser.cpp - HDRS - parser.h - DEPENDS - .core_structs - libc.src.__support.arg_list - libc.src.__support.ctype_utils - libc.src.__support.str_to_integer - libc.src.__support.CPP.bit - libc.src.__support.CPP.optional - libc.src.__support.CPP.string_view - libc.src.__support.CPP.type_traits - libc.src.__support.common -) - -add_object_library( - mock_parser - SRCS - parser.cpp HDRS parser.h DEPENDS @@ -42,8 +22,6 @@ add_object_library( libc.src.__support.CPP.string_view libc.src.__support.CPP.type_traits libc.src.__support.common - COMPILE_OPTIONS - -DLIBC_COPT_MOCK_ARG_LIST ) add_object_library( diff --git a/libc/src/stdio/printf_core/parser.cpp b/libc/src/stdio/printf_core/parser.cpp deleted file mode 100644 index 6b2c174c3f233..0000000000000 --- a/libc/src/stdio/printf_core/parser.cpp +++ /dev/null @@ -1,466 +0,0 @@ -//===-- Format string parser implementation for printf ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// #define LIBC_COPT_PRINTF_DISABLE_INDEX_MODE 1 // This will be a compile flag. - -#include "parser.h" - -#include "src/__support/arg_list.h" - -#include "src/__support/CPP/bit.h" -#include "src/__support/CPP/optional.h" -#include "src/__support/CPP/string_view.h" -#include "src/__support/CPP/type_traits.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/ctype_utils.h" -#include "src/__support/str_to_integer.h" -#include "src/stdio/printf_core/core_structs.h" - -namespace __llvm_libc { -namespace printf_core { - -template struct int_type_of { - using type = T; -}; -template <> struct int_type_of { - using type = fputil::FPBits::UIntType; -}; -template <> struct int_type_of { - using type = fputil::FPBits::UIntType; -}; -template using int_type_of_v = typename int_type_of::type; - -#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE -#define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, index) \ - { \ - auto temp = get_arg_value(index); \ - if (!temp.has_value()) { \ - section.has_conv = false; \ - } else { \ - dst = cpp::bit_cast>(temp.value()); \ - } \ - } -#else -#define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, _) \ - dst = cpp::bit_cast>(get_next_arg_value()) -#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - -FormatSection Parser::get_next_section() { - FormatSection section; - size_t starting_pos = cur_pos; - if (str[cur_pos] == '%') { - // format section - section.has_conv = true; - - ++cur_pos; - [[maybe_unused]] size_t conv_index = 0; - -#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - conv_index = parse_index(&cur_pos); -#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - - section.flags = parse_flags(&cur_pos); - - // handle width - section.min_width = 0; - if (str[cur_pos] == '*') { - ++cur_pos; - - WRITE_ARG_VAL_SIMPLEST(section.min_width, int, parse_index(&cur_pos)); - } else if (internal::isdigit(str[cur_pos])) { - auto result = internal::strtointeger(str + cur_pos, 10); - section.min_width = result.value; - cur_pos = cur_pos + result.parsed_len; - } - if (section.min_width < 0) { - section.min_width = -section.min_width; - section.flags = - static_cast(section.flags | FormatFlags::LEFT_JUSTIFIED); - } - - // handle precision - section.precision = -1; // negative precisions are ignored. - if (str[cur_pos] == '.') { - ++cur_pos; - section.precision = 0; // if there's a . but no specified precision, the - // precision is implicitly 0. - if (str[cur_pos] == '*') { - ++cur_pos; - - WRITE_ARG_VAL_SIMPLEST(section.precision, int, parse_index(&cur_pos)); - - } else if (internal::isdigit(str[cur_pos])) { - auto result = internal::strtointeger(str + cur_pos, 10); - section.precision = result.value; - cur_pos = cur_pos + result.parsed_len; - } - } - - LengthModifier lm = parse_length_modifier(&cur_pos); - - section.length_modifier = lm; - section.conv_name = str[cur_pos]; - switch (str[cur_pos]) { - case ('%'): - // Regardless of options, a % conversion is always safe. The standard says - // that "The complete conversion specification shall be %%" but it also - // says that "If a conversion specification is invalid, the behavior is - // undefined." Based on that we define that any conversion specification - // ending in '%' shall display as '%' regardless of any valid or invalid - // options. - section.has_conv = true; - break; - case ('c'): - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); - break; - case ('d'): - case ('i'): - case ('o'): - case ('x'): - case ('X'): - case ('u'): - switch (lm) { - case (LengthModifier::hh): - case (LengthModifier::h): - case (LengthModifier::none): - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); - break; - case (LengthModifier::l): - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long, conv_index); - break; - case (LengthModifier::ll): - case (LengthModifier::L): // This isn't in the standard, but is in other - // libc implementations. - - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long long, conv_index); - break; - case (LengthModifier::j): - - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index); - break; - case (LengthModifier::z): - - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, size_t, conv_index); - break; - case (LengthModifier::t): - - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, ptrdiff_t, conv_index); - break; - } - break; -#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT - case ('f'): - case ('F'): - case ('e'): - case ('E'): - case ('a'): - case ('A'): - case ('g'): - case ('G'): - if (lm != LengthModifier::L) { - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index); - } else { - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index); - } - break; -#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT -#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case ('n'): -#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case ('p'): - case ('s'): - WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index); - break; - default: - // if the conversion is undefined, change this to a raw section. - section.has_conv = false; - break; - } - // If the end of the format section is on the '\0'. This means we need to - // not advance the cur_pos. - if (str[cur_pos] != '\0') - ++cur_pos; - - } else { - // raw section - section.has_conv = false; - while (str[cur_pos] != '%' && str[cur_pos] != '\0') - ++cur_pos; - } - section.raw_string = {str + starting_pos, cur_pos - starting_pos}; - return section; -} - -FormatFlags Parser::parse_flags(size_t *local_pos) { - bool found_flag = true; - FormatFlags flags = FormatFlags(0); - while (found_flag) { - switch (str[*local_pos]) { - case '-': - flags = static_cast(flags | FormatFlags::LEFT_JUSTIFIED); - break; - case '+': - flags = static_cast(flags | FormatFlags::FORCE_SIGN); - break; - case ' ': - flags = static_cast(flags | FormatFlags::SPACE_PREFIX); - break; - case '#': - flags = static_cast(flags | FormatFlags::ALTERNATE_FORM); - break; - case '0': - flags = static_cast(flags | FormatFlags::LEADING_ZEROES); - break; - default: - found_flag = false; - } - if (found_flag) - ++*local_pos; - } - return flags; -} - -LengthModifier Parser::parse_length_modifier(size_t *local_pos) { - switch (str[*local_pos]) { - case ('l'): - if (str[*local_pos + 1] == 'l') { - *local_pos += 2; - return LengthModifier::ll; - } else { - ++*local_pos; - return LengthModifier::l; - } - case ('h'): - if (str[*local_pos + 1] == 'h') { - *local_pos += 2; - return LengthModifier::hh; - } else { - ++*local_pos; - return LengthModifier::h; - } - case ('L'): - ++*local_pos; - return LengthModifier::L; - case ('j'): - ++*local_pos; - return LengthModifier::j; - case ('z'): - ++*local_pos; - return LengthModifier::z; - case ('t'): - ++*local_pos; - return LengthModifier::t; - default: - return LengthModifier::none; - } -} - -//---------------------------------------------------- -// INDEX MODE ONLY FUNCTIONS AFTER HERE: -//---------------------------------------------------- - -#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - -size_t Parser::parse_index(size_t *local_pos) { - if (internal::isdigit(str[*local_pos])) { - auto result = internal::strtointeger(str + *local_pos, 10); - size_t index = result.value; - if (str[*local_pos + result.parsed_len] != '$') - return 0; - *local_pos = 1 + result.parsed_len + *local_pos; - return index; - } - return 0; -} - -TypeDesc Parser::get_type_desc(size_t index) { - // index mode is assumed, and the indicies start at 1, so an index - // of 0 is invalid. - size_t local_pos = 0; - - while (str[local_pos]) { - if (str[local_pos] == '%') { - ++local_pos; - - size_t conv_index = parse_index(&local_pos); - - // the flags aren't relevant for this situation, but I need to skip past - // them so they're parsed but the result is discarded. - parse_flags(&local_pos); - - // handle width - if (str[local_pos] == '*') { - ++local_pos; - - size_t width_index = parse_index(&local_pos); - set_type_desc(width_index, type_desc_from_type()); - if (width_index == index) - return type_desc_from_type(); - - } else if (internal::isdigit(str[local_pos])) { - while (internal::isdigit(str[local_pos])) - ++local_pos; - } - - // handle precision - if (str[local_pos] == '.') { - ++local_pos; - if (str[local_pos] == '*') { - ++local_pos; - - size_t precision_index = parse_index(&local_pos); - set_type_desc(precision_index, type_desc_from_type()); - if (precision_index == index) - return type_desc_from_type(); - - } else if (internal::isdigit(str[local_pos])) { - while (internal::isdigit(str[local_pos])) - ++local_pos; - } - } - - LengthModifier lm = parse_length_modifier(&local_pos); - - // if we don't have an index for this conversion, then its position is - // unknown and all this information is irrelevant. The rest of this logic - // has been for skipping past this conversion properly to avoid - // weirdness with %%. - if (conv_index == 0) { - if (str[local_pos] != '\0') - ++local_pos; - continue; - } - - TypeDesc conv_size = type_desc_from_type(); - switch (str[local_pos]) { - case ('%'): - conv_size = type_desc_from_type(); - break; - case ('c'): - conv_size = type_desc_from_type(); - break; - case ('d'): - case ('i'): - case ('o'): - case ('x'): - case ('X'): - case ('u'): - switch (lm) { - case (LengthModifier::hh): - case (LengthModifier::h): - case (LengthModifier::none): - conv_size = type_desc_from_type(); - break; - case (LengthModifier::l): - conv_size = type_desc_from_type(); - break; - case (LengthModifier::ll): - case (LengthModifier::L): // This isn't in the standard, but is in other - // libc implementations. - conv_size = type_desc_from_type(); - break; - case (LengthModifier::j): - conv_size = type_desc_from_type(); - break; - case (LengthModifier::z): - conv_size = type_desc_from_type(); - break; - case (LengthModifier::t): - conv_size = type_desc_from_type(); - break; - } - break; -#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT - case ('f'): - case ('F'): - case ('e'): - case ('E'): - case ('a'): - case ('A'): - case ('g'): - case ('G'): - if (lm != LengthModifier::L) - conv_size = type_desc_from_type(); - else - conv_size = type_desc_from_type(); - break; -#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT -#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case ('n'): -#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case ('p'): - case ('s'): - conv_size = type_desc_from_type(); - break; - default: - conv_size = type_desc_from_type(); - break; - } - - set_type_desc(conv_index, conv_size); - if (conv_index == index) - return conv_size; - } - // If the end of the format section is on the '\0'. This means we need to - // not advance the local_pos. - if (str[local_pos] != '\0') - ++local_pos; - } - - // If there is no size for the requested index, then it's unknown. Return - // void. - return type_desc_from_type(); -} - -bool Parser::args_to_index(size_t index) { - if (args_index > index) { - args_index = 1; - args_cur = args_start; - } - - while (args_index < index) { - TypeDesc cur_type_desc = type_desc_from_type(); - if (args_index <= DESC_ARR_LEN) - cur_type_desc = desc_arr[args_index - 1]; - - if (cur_type_desc == type_desc_from_type()) - cur_type_desc = get_type_desc(args_index); - - // A type of void represents the type being unknown. If the type for the - // requested index isn't in the desc_arr and isn't found by parsing the - // string, then then advancing to the requested index is impossible. In that - // case the function returns false. - if (cur_type_desc == type_desc_from_type()) - return false; - - if (cur_type_desc == type_desc_from_type()) - args_cur.next_var(); - else if (cur_type_desc == type_desc_from_type()) - args_cur.next_var(); -#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT - // Floating point numbers are stored separately from the other arguments. - else if (cur_type_desc == type_desc_from_type()) - args_cur.next_var(); - else if (cur_type_desc == type_desc_from_type()) - args_cur.next_var(); -#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT - // pointers may be stored separately from normal values. - else if (cur_type_desc == type_desc_from_type()) - args_cur.next_var(); - else - args_cur.next_var(); - - ++args_index; - } - return true; -} - -#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - -} // namespace printf_core -} // namespace __llvm_libc diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h index a376af99ad8d7..ddffe9694b667 100644 --- a/libc/src/stdio/printf_core/parser.h +++ b/libc/src/stdio/printf_core/parser.h @@ -13,6 +13,7 @@ #include "src/__support/CPP/type_traits.h" #include "src/__support/arg_list.h" #include "src/__support/common.h" +#include "src/__support/str_to_integer.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_config.h" @@ -21,13 +22,33 @@ namespace __llvm_libc { namespace printf_core { -#ifndef LIBC_COPT_MOCK_ARG_LIST -using ArgProvider = internal::ArgList; -#else // not defined LIBC_COPT_MOCK_ARG_LIST -using ArgProvider = internal::MockArgList; -#endif // LIBC_COPT_MOCK_ARG_LIST +template struct int_type_of { + using type = T; +}; +template <> struct int_type_of { + using type = fputil::FPBits::UIntType; +}; +template <> struct int_type_of { + using type = fputil::FPBits::UIntType; +}; +template using int_type_of_v = typename int_type_of::type; -class Parser { +#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE +#define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, index) \ + { \ + auto temp = get_arg_value(index); \ + if (!temp.has_value()) { \ + section.has_conv = false; \ + } else { \ + dst = cpp::bit_cast>(temp.value()); \ + } \ + } +#else +#define WRITE_ARG_VAL_SIMPLEST(dst, arg_type, _) \ + dst = cpp::bit_cast>(get_next_arg_value()) +#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE + +template class Parser { const char *__restrict str; size_t cur_pos = 0; @@ -67,24 +88,230 @@ class Parser { // specified format section. This can either be a raw format section with no // conversion, or a format section with a conversion that has all of its // variables stored in the format section. - FormatSection get_next_section(); + LIBC_INLINE FormatSection get_next_section() { + FormatSection section; + size_t starting_pos = cur_pos; + if (str[cur_pos] == '%') { + // format section + section.has_conv = true; + + ++cur_pos; + [[maybe_unused]] size_t conv_index = 0; + +#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE + conv_index = parse_index(&cur_pos); +#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE + + section.flags = parse_flags(&cur_pos); + + // handle width + section.min_width = 0; + if (str[cur_pos] == '*') { + ++cur_pos; + + WRITE_ARG_VAL_SIMPLEST(section.min_width, int, parse_index(&cur_pos)); + } else if (internal::isdigit(str[cur_pos])) { + auto result = internal::strtointeger(str + cur_pos, 10); + section.min_width = result.value; + cur_pos = cur_pos + result.parsed_len; + } + if (section.min_width < 0) { + section.min_width = -section.min_width; + section.flags = static_cast(section.flags | + FormatFlags::LEFT_JUSTIFIED); + } + + // handle precision + section.precision = -1; // negative precisions are ignored. + if (str[cur_pos] == '.') { + ++cur_pos; + section.precision = 0; // if there's a . but no specified precision, the + // precision is implicitly 0. + if (str[cur_pos] == '*') { + ++cur_pos; + + WRITE_ARG_VAL_SIMPLEST(section.precision, int, parse_index(&cur_pos)); + + } else if (internal::isdigit(str[cur_pos])) { + auto result = internal::strtointeger(str + cur_pos, 10); + section.precision = result.value; + cur_pos = cur_pos + result.parsed_len; + } + } + + LengthModifier lm = parse_length_modifier(&cur_pos); + + section.length_modifier = lm; + section.conv_name = str[cur_pos]; + switch (str[cur_pos]) { + case ('%'): + // Regardless of options, a % conversion is always safe. The standard + // says that "The complete conversion specification shall be %%" but it + // also says that "If a conversion specification is invalid, the + // behavior is undefined." Based on that we define that any conversion + // specification ending in '%' shall display as '%' regardless of any + // valid or invalid options. + section.has_conv = true; + break; + case ('c'): + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); + break; + case ('d'): + case ('i'): + case ('o'): + case ('x'): + case ('X'): + case ('u'): + switch (lm) { + case (LengthModifier::hh): + case (LengthModifier::h): + case (LengthModifier::none): + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); + break; + case (LengthModifier::l): + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long, conv_index); + break; + case (LengthModifier::ll): + case (LengthModifier::L): // This isn't in the standard, but is in other + // libc implementations. + + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long long, conv_index); + break; + case (LengthModifier::j): + + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, intmax_t, conv_index); + break; + case (LengthModifier::z): + + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, size_t, conv_index); + break; + case (LengthModifier::t): + + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, ptrdiff_t, conv_index); + break; + } + break; +#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT + case ('f'): + case ('F'): + case ('e'): + case ('E'): + case ('a'): + case ('A'): + case ('g'): + case ('G'): + if (lm != LengthModifier::L) { + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index); + } else { + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index); + } + break; +#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT +#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT + case ('n'): +#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT + case ('p'): + WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index); + break; + case ('s'): + WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, char *, conv_index); + break; + default: + // if the conversion is undefined, change this to a raw section. + section.has_conv = false; + break; + } + // If the end of the format section is on the '\0'. This means we need to + // not advance the cur_pos. + if (str[cur_pos] != '\0') + ++cur_pos; + + } else { + // raw section + section.has_conv = false; + while (str[cur_pos] != '%' && str[cur_pos] != '\0') + ++cur_pos; + } + section.raw_string = {str + starting_pos, cur_pos - starting_pos}; + return section; + } private: // parse_flags parses the flags inside a format string. It assumes that // str[*local_pos] is inside a format specifier, and parses any flags it // finds. It returns a FormatFlags object containing the set of found flags // arithmetically or'd together. local_pos will be moved past any flags found. - FormatFlags parse_flags(size_t *local_pos); + LIBC_INLINE FormatFlags parse_flags(size_t *local_pos) { + bool found_flag = true; + FormatFlags flags = FormatFlags(0); + while (found_flag) { + switch (str[*local_pos]) { + case '-': + flags = static_cast(flags | FormatFlags::LEFT_JUSTIFIED); + break; + case '+': + flags = static_cast(flags | FormatFlags::FORCE_SIGN); + break; + case ' ': + flags = static_cast(flags | FormatFlags::SPACE_PREFIX); + break; + case '#': + flags = static_cast(flags | FormatFlags::ALTERNATE_FORM); + break; + case '0': + flags = static_cast(flags | FormatFlags::LEADING_ZEROES); + break; + default: + found_flag = false; + } + if (found_flag) + ++*local_pos; + } + return flags; + } // parse_length_modifier parses the length modifier inside a format string. It // assumes that str[*local_pos] is inside a format specifier. It returns a // LengthModifier with the length modifier it found. It will advance local_pos // after the format specifier if one is found. - LengthModifier parse_length_modifier(size_t *local_pos); + LIBC_INLINE LengthModifier parse_length_modifier(size_t *local_pos) { + switch (str[*local_pos]) { + case ('l'): + if (str[*local_pos + 1] == 'l') { + *local_pos += 2; + return LengthModifier::ll; + } else { + ++*local_pos; + return LengthModifier::l; + } + case ('h'): + if (str[*local_pos + 1] == 'h') { + *local_pos += 2; + return LengthModifier::hh; + } else { + ++*local_pos; + return LengthModifier::h; + } + case ('L'): + ++*local_pos; + return LengthModifier::L; + case ('j'): + ++*local_pos; + return LengthModifier::j; + case ('z'): + ++*local_pos; + return LengthModifier::z; + case ('t'): + ++*local_pos; + return LengthModifier::t; + default: + return LengthModifier::none; + } + } // get_next_arg_value gets the next value from the arg list as type T. template LIBC_INLINE T get_next_arg_value() { - return args_cur.next_var(); + return args_cur.template next_var(); } //---------------------------------------------------- @@ -98,7 +325,17 @@ class Parser { // returns 0 if there is no closing $, or if it finds no number. If it finds a // number, it will move local_pos past the end of the $, else it will not move // local_pos. - size_t parse_index(size_t *local_pos); + LIBC_INLINE size_t parse_index(size_t *local_pos) { + if (internal::isdigit(str[*local_pos])) { + auto result = internal::strtointeger(str + *local_pos, 10); + size_t index = result.value; + if (str[*local_pos + result.parsed_len] != '$') + return 0; + *local_pos = 1 + result.parsed_len + *local_pos; + return index; + } + return 0; + } LIBC_INLINE void set_type_desc(size_t index, TypeDesc value) { if (index != 0 && index <= DESC_ARR_LEN) @@ -131,13 +368,191 @@ class Parser { // It moves cur_args to the index requested so the appropriate value may // be read. This may involve parsing the format string, and is in the worst // case an O(n^2) operation. - bool args_to_index(size_t index); + LIBC_INLINE bool args_to_index(size_t index) { + if (args_index > index) { + args_index = 1; + args_cur = args_start; + } + + while (args_index < index) { + TypeDesc cur_type_desc = type_desc_from_type(); + if (args_index <= DESC_ARR_LEN) + cur_type_desc = desc_arr[args_index - 1]; + + if (cur_type_desc == type_desc_from_type()) + cur_type_desc = get_type_desc(args_index); + + // A type of void represents the type being unknown. If the type for the + // requested index isn't in the desc_arr and isn't found by parsing the + // string, then then advancing to the requested index is impossible. In + // that case the function returns false. + if (cur_type_desc == type_desc_from_type()) + return false; + + if (cur_type_desc == type_desc_from_type()) + args_cur.template next_var(); + else if (cur_type_desc == type_desc_from_type()) + args_cur.template next_var(); +#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT + // Floating point numbers are stored separately from the other arguments. + else if (cur_type_desc == type_desc_from_type()) + args_cur.template next_var(); + else if (cur_type_desc == type_desc_from_type()) + args_cur.template next_var(); +#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT + // pointers may be stored separately from normal values. + else if (cur_type_desc == type_desc_from_type()) + args_cur.template next_var(); + else + args_cur.template next_var(); + + ++args_index; + } + return true; + } // get_type_desc assumes that this format string uses index mode. It iterates // through the format string until it finds a format specifier that defines // the type of index, and returns a TypeDesc describing that type. It does not // modify cur_pos. - TypeDesc get_type_desc(size_t index); + LIBC_INLINE TypeDesc get_type_desc(size_t index) { + // index mode is assumed, and the indicies start at 1, so an index + // of 0 is invalid. + size_t local_pos = 0; + + while (str[local_pos]) { + if (str[local_pos] == '%') { + ++local_pos; + + size_t conv_index = parse_index(&local_pos); + + // the flags aren't relevant for this situation, but I need to skip past + // them so they're parsed but the result is discarded. + parse_flags(&local_pos); + + // handle width + if (str[local_pos] == '*') { + ++local_pos; + + size_t width_index = parse_index(&local_pos); + set_type_desc(width_index, type_desc_from_type()); + if (width_index == index) + return type_desc_from_type(); + + } else if (internal::isdigit(str[local_pos])) { + while (internal::isdigit(str[local_pos])) + ++local_pos; + } + + // handle precision + if (str[local_pos] == '.') { + ++local_pos; + if (str[local_pos] == '*') { + ++local_pos; + + size_t precision_index = parse_index(&local_pos); + set_type_desc(precision_index, type_desc_from_type()); + if (precision_index == index) + return type_desc_from_type(); + + } else if (internal::isdigit(str[local_pos])) { + while (internal::isdigit(str[local_pos])) + ++local_pos; + } + } + + LengthModifier lm = parse_length_modifier(&local_pos); + + // if we don't have an index for this conversion, then its position is + // unknown and all this information is irrelevant. The rest of this + // logic has been for skipping past this conversion properly to avoid + // weirdness with %%. + if (conv_index == 0) { + if (str[local_pos] != '\0') + ++local_pos; + continue; + } + + TypeDesc conv_size = type_desc_from_type(); + switch (str[local_pos]) { + case ('%'): + conv_size = type_desc_from_type(); + break; + case ('c'): + conv_size = type_desc_from_type(); + break; + case ('d'): + case ('i'): + case ('o'): + case ('x'): + case ('X'): + case ('u'): + switch (lm) { + case (LengthModifier::hh): + case (LengthModifier::h): + case (LengthModifier::none): + conv_size = type_desc_from_type(); + break; + case (LengthModifier::l): + conv_size = type_desc_from_type(); + break; + case (LengthModifier::ll): + case (LengthModifier::L): // This isn't in the standard, but is in + // other libc implementations. + conv_size = type_desc_from_type(); + break; + case (LengthModifier::j): + conv_size = type_desc_from_type(); + break; + case (LengthModifier::z): + conv_size = type_desc_from_type(); + break; + case (LengthModifier::t): + conv_size = type_desc_from_type(); + break; + } + break; +#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT + case ('f'): + case ('F'): + case ('e'): + case ('E'): + case ('a'): + case ('A'): + case ('g'): + case ('G'): + if (lm != LengthModifier::L) + conv_size = type_desc_from_type(); + else + conv_size = type_desc_from_type(); + break; +#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT +#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT + case ('n'): +#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT + case ('p'): + case ('s'): + conv_size = type_desc_from_type(); + break; + default: + conv_size = type_desc_from_type(); + break; + } + + set_type_desc(conv_index, conv_size); + if (conv_index == index) + return conv_size; + } + // If the end of the format section is on the '\0'. This means we need to + // not advance the local_pos. + if (str[local_pos] != '\0') + ++local_pos; + } + + // If there is no size for the requested index, then it's unknown. Return + // void. + return type_desc_from_type(); + } #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE }; diff --git a/libc/src/stdio/printf_core/printf_main.cpp b/libc/src/stdio/printf_core/printf_main.cpp index b7684cdf1e74f..60d1e210eee4c 100644 --- a/libc/src/stdio/printf_core/printf_main.cpp +++ b/libc/src/stdio/printf_core/printf_main.cpp @@ -21,7 +21,7 @@ namespace printf_core { int printf_main(Writer *writer, const char *__restrict str, internal::ArgList &args) { - Parser parser(str, args); + Parser parser(str, args); int result = 0; for (FormatSection cur_section = parser.get_next_section(); !cur_section.raw_string.empty(); diff --git a/libc/src/stdio/scanf_core/CMakeLists.txt b/libc/src/stdio/scanf_core/CMakeLists.txt index 9f6cb9c386eb2..8cdd33e5c2c0f 100644 --- a/libc/src/stdio/scanf_core/CMakeLists.txt +++ b/libc/src/stdio/scanf_core/CMakeLists.txt @@ -8,10 +8,8 @@ add_header_library( libc.src.__support.FPUtil.fp_bits ) -add_object_library( +add_header_library( parser - SRCS - parser.cpp HDRS parser.h DEPENDS diff --git a/libc/src/stdio/scanf_core/parser.cpp b/libc/src/stdio/scanf_core/parser.cpp deleted file mode 100644 index 44e853c8a8de8..0000000000000 --- a/libc/src/stdio/scanf_core/parser.cpp +++ /dev/null @@ -1,225 +0,0 @@ -//===-- Format string parser implementation for scanf ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// #define LIBC_COPT_SCANF_DISABLE_INDEX_MODE 1 // This will be a compile flag. - -#include "src/stdio/scanf_core/parser.h" - -#include "src/__support/arg_list.h" - -#include "src/__support/CPP/bit.h" -#include "src/__support/CPP/bitset.h" -#include "src/__support/CPP/string_view.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/ctype_utils.h" -#include "src/__support/str_to_integer.h" - -namespace __llvm_libc { -namespace scanf_core { - -#ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE -#define GET_ARG_VAL_SIMPLEST(arg_type, index) get_arg_value(index) -#else -#define GET_ARG_VAL_SIMPLEST(arg_type, _) get_next_arg_value() -#endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE - -FormatSection Parser::get_next_section() { - FormatSection section; - size_t starting_pos = cur_pos; - if (str[cur_pos] == '%') { - // format section - section.has_conv = true; - - ++cur_pos; - [[maybe_unused]] size_t conv_index = 0; - -#ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE - conv_index = parse_index(&cur_pos); -#endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE - - if (str[cur_pos] == '*') { - ++cur_pos; - section.flags = FormatFlags::NO_WRITE; - } - - // handle width - section.max_width = -1; - if (internal::isdigit(str[cur_pos])) { - auto result = internal::strtointeger(str + cur_pos, 10); - section.max_width = result.value; - cur_pos = cur_pos + result.parsed_len; - } - - // TODO(michaelrj): add posix allocate flag support. - // if (str[cur_pos] == 'm') { - // ++cur_pos; - // section.flags = FormatFlags::ALLOCATE; - // } - - LengthModifier lm = parse_length_modifier(&cur_pos); - section.length_modifier = lm; - - section.conv_name = str[cur_pos]; - - // If NO_WRITE is not set, then read the next arg as the output pointer. - if ((section.flags & FormatFlags::NO_WRITE) == 0) { - // Since all outputs are pointers, there's no need to distinguish when - // reading from va_args. They're all the same size and stored the same. - section.output_ptr = GET_ARG_VAL_SIMPLEST(void *, conv_index); - } - - // If the end of the format section is on the '\0'. This means we need to - // not advance the cur_pos and we should not count this has having a - // conversion. - if (str[cur_pos] != '\0') { - ++cur_pos; - } else { - section.has_conv = false; - } - - // If the format is a bracketed one, then we need to parse out the insides - // of the brackets. - if (section.conv_name == '[') { - constexpr char CLOSING_BRACKET = ']'; - constexpr char INVERT_FLAG = '^'; - constexpr char RANGE_OPERATOR = '-'; - - cpp::bitset<256> scan_set; - bool invert = false; - - // The circumflex in the first position represents the inversion flag, but - // it's easier to apply that at the end so we just store it for now. - if (str[cur_pos] == INVERT_FLAG) { - invert = true; - ++cur_pos; - } - - // This is used to determine if a hyphen is being used as a literal or as - // a range operator. - size_t set_start_pos = cur_pos; - - // Normally the right bracket closes the set, but if it's the first - // character (possibly after the inversion flag) then it's instead - // included as a character in the set and the second right bracket closes - // the set. - if (str[cur_pos] == CLOSING_BRACKET) { - scan_set.set(CLOSING_BRACKET); - ++cur_pos; - } - - while (str[cur_pos] != '\0' && str[cur_pos] != CLOSING_BRACKET) { - // If a hyphen is being used as a range operator, since it's neither at - // the beginning nor end of the set. - if (str[cur_pos] == RANGE_OPERATOR && cur_pos != set_start_pos && - str[cur_pos + 1] != CLOSING_BRACKET && str[cur_pos + 1] != '\0') { - // Technically there is no requirement to correct the ordering of the - // range, but since the range operator is entirely implementation - // defined it seems like a good convenience. - char a = str[cur_pos - 1]; - char b = str[cur_pos + 1]; - char start = (a < b ? a : b); - char end = (a < b ? b : a); - scan_set.set_range(start, end); - cur_pos += 2; - } else { - scan_set.set(str[cur_pos]); - ++cur_pos; - } - } - if (invert) - scan_set.flip(); - - if (str[cur_pos] == CLOSING_BRACKET) { - ++cur_pos; - section.scan_set = scan_set; - } else { - // if the end of the string was encountered, this is not a valid set. - section.has_conv = false; - } - } - } else { - // raw section - section.has_conv = false; - while (str[cur_pos] != '%' && str[cur_pos] != '\0') - ++cur_pos; - } - section.raw_string = {str + starting_pos, cur_pos - starting_pos}; - return section; -} - -LengthModifier Parser::parse_length_modifier(size_t *local_pos) { - switch (str[*local_pos]) { - case ('l'): - if (str[*local_pos + 1] == 'l') { - *local_pos += 2; - return LengthModifier::ll; - } else { - ++*local_pos; - return LengthModifier::l; - } - case ('h'): - if (str[*local_pos + 1] == 'h') { - *local_pos += 2; - return LengthModifier::hh; - } else { - ++*local_pos; - return LengthModifier::h; - } - case ('L'): - ++*local_pos; - return LengthModifier::L; - case ('j'): - ++*local_pos; - return LengthModifier::j; - case ('z'): - ++*local_pos; - return LengthModifier::z; - case ('t'): - ++*local_pos; - return LengthModifier::t; - default: - return LengthModifier::NONE; - } -} - -//---------------------------------------------------- -// INDEX MODE ONLY FUNCTIONS AFTER HERE: -//---------------------------------------------------- - -#ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE - -size_t Parser::parse_index(size_t *local_pos) { - if (internal::isdigit(str[*local_pos])) { - auto result = internal::strtointeger(str + *local_pos, 10); - size_t index = result.value; - if (str[*local_pos + result.parsed_len] != '$') - return 0; - *local_pos = 1 + result.parsed_len + *local_pos; - return index; - } - return 0; -} - -void Parser::args_to_index(size_t index) { - if (args_index > index) { - args_index = 1; - args_cur = args_start; - } - - while (args_index < index) { - // Since all arguments must be pointers, we can just read all of them as - // void * and not worry about type issues. - args_cur.next_var(); - ++args_index; - } -} - -#endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE - -} // namespace scanf_core -} // namespace __llvm_libc diff --git a/libc/src/stdio/scanf_core/parser.h b/libc/src/stdio/scanf_core/parser.h index 4b9f0b4dd95b9..f0cebc8de1c36 100644 --- a/libc/src/stdio/scanf_core/parser.h +++ b/libc/src/stdio/scanf_core/parser.h @@ -11,6 +11,8 @@ #include "src/__support/arg_list.h" #include "src/__support/common.h" +#include "src/__support/ctype_utils.h" +#include "src/__support/str_to_integer.h" #include "src/stdio/scanf_core/core_structs.h" #include "src/stdio/scanf_core/scanf_config.h" @@ -19,17 +21,23 @@ namespace __llvm_libc { namespace scanf_core { -class Parser { +#ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE +#define GET_ARG_VAL_SIMPLEST(arg_type, index) get_arg_value(index) +#else +#define GET_ARG_VAL_SIMPLEST(arg_type, _) get_next_arg_value() +#endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE + +template class Parser { const char *__restrict str; size_t cur_pos = 0; - internal::ArgList args_cur; + ArgProvider args_cur; #ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE // args_start stores the start of the va_args, which is used when a previous // argument is needed. In that case, we have to read the arguments from the // beginning since they don't support reading backwards. - internal::ArgList args_start; + ArgProvider args_start; size_t args_index = 1; #endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE @@ -46,18 +54,173 @@ class Parser { // specified format section. This can either be a raw format section with no // conversion, or a format section with a conversion that has all of its // variables stored in the format section. - FormatSection get_next_section(); + LIBC_INLINE FormatSection get_next_section() { + FormatSection section; + size_t starting_pos = cur_pos; + if (str[cur_pos] == '%') { + // format section + section.has_conv = true; + + ++cur_pos; + [[maybe_unused]] size_t conv_index = 0; + +#ifndef LIBC_COPT_SCANF_DISABLE_INDEX_MODE + conv_index = parse_index(&cur_pos); +#endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE + + if (str[cur_pos] == '*') { + ++cur_pos; + section.flags = FormatFlags::NO_WRITE; + } + + // handle width + section.max_width = -1; + if (internal::isdigit(str[cur_pos])) { + auto result = internal::strtointeger(str + cur_pos, 10); + section.max_width = result.value; + cur_pos = cur_pos + result.parsed_len; + } + + // TODO(michaelrj): add posix allocate flag support. + // if (str[cur_pos] == 'm') { + // ++cur_pos; + // section.flags = FormatFlags::ALLOCATE; + // } + + LengthModifier lm = parse_length_modifier(&cur_pos); + section.length_modifier = lm; + + section.conv_name = str[cur_pos]; + + // If NO_WRITE is not set, then read the next arg as the output pointer. + if ((section.flags & FormatFlags::NO_WRITE) == 0) { + // Since all outputs are pointers, there's no need to distinguish when + // reading from va_args. They're all the same size and stored the same. + section.output_ptr = GET_ARG_VAL_SIMPLEST(void *, conv_index); + } + + // If the end of the format section is on the '\0'. This means we need to + // not advance the cur_pos and we should not count this has having a + // conversion. + if (str[cur_pos] != '\0') { + ++cur_pos; + } else { + section.has_conv = false; + } + + // If the format is a bracketed one, then we need to parse out the insides + // of the brackets. + if (section.conv_name == '[') { + constexpr char CLOSING_BRACKET = ']'; + constexpr char INVERT_FLAG = '^'; + constexpr char RANGE_OPERATOR = '-'; + + cpp::bitset<256> scan_set; + bool invert = false; + + // The circumflex in the first position represents the inversion flag, + // but it's easier to apply that at the end so we just store it for now. + if (str[cur_pos] == INVERT_FLAG) { + invert = true; + ++cur_pos; + } + + // This is used to determine if a hyphen is being used as a literal or + // as a range operator. + size_t set_start_pos = cur_pos; + + // Normally the right bracket closes the set, but if it's the first + // character (possibly after the inversion flag) then it's instead + // included as a character in the set and the second right bracket + // closes the set. + if (str[cur_pos] == CLOSING_BRACKET) { + scan_set.set(CLOSING_BRACKET); + ++cur_pos; + } + + while (str[cur_pos] != '\0' && str[cur_pos] != CLOSING_BRACKET) { + // If a hyphen is being used as a range operator, since it's neither + // at the beginning nor end of the set. + if (str[cur_pos] == RANGE_OPERATOR && cur_pos != set_start_pos && + str[cur_pos + 1] != CLOSING_BRACKET && str[cur_pos + 1] != '\0') { + // Technically there is no requirement to correct the ordering of + // the range, but since the range operator is entirely + // implementation defined it seems like a good convenience. + char a = str[cur_pos - 1]; + char b = str[cur_pos + 1]; + char start = (a < b ? a : b); + char end = (a < b ? b : a); + scan_set.set_range(start, end); + cur_pos += 2; + } else { + scan_set.set(str[cur_pos]); + ++cur_pos; + } + } + if (invert) + scan_set.flip(); + + if (str[cur_pos] == CLOSING_BRACKET) { + ++cur_pos; + section.scan_set = scan_set; + } else { + // if the end of the string was encountered, this is not a valid set. + section.has_conv = false; + } + } + } else { + // raw section + section.has_conv = false; + while (str[cur_pos] != '%' && str[cur_pos] != '\0') + ++cur_pos; + } + section.raw_string = {str + starting_pos, cur_pos - starting_pos}; + return section; + } private: // parse_length_modifier parses the length modifier inside a format string. It // assumes that str[*local_pos] is inside a format specifier. It returns a // LengthModifier with the length modifier it found. It will advance local_pos // after the format specifier if one is found. - LengthModifier parse_length_modifier(size_t *local_pos); + LIBC_INLINE LengthModifier parse_length_modifier(size_t *local_pos) { + switch (str[*local_pos]) { + case ('l'): + if (str[*local_pos + 1] == 'l') { + *local_pos += 2; + return LengthModifier::ll; + } else { + ++*local_pos; + return LengthModifier::l; + } + case ('h'): + if (str[*local_pos + 1] == 'h') { + *local_pos += 2; + return LengthModifier::hh; + } else { + ++*local_pos; + return LengthModifier::h; + } + case ('L'): + ++*local_pos; + return LengthModifier::L; + case ('j'): + ++*local_pos; + return LengthModifier::j; + case ('z'): + ++*local_pos; + return LengthModifier::z; + case ('t'): + ++*local_pos; + return LengthModifier::t; + default: + return LengthModifier::NONE; + } + } // get_next_arg_value gets the next value from the arg list as type T. template LIBC_INLINE T get_next_arg_value() { - return args_cur.next_var(); + return args_cur.template next_var(); } //---------------------------------------------------- @@ -71,7 +234,17 @@ class Parser { // returns 0 if there is no closing $, or if it finds no number. If it finds a // number, it will move local_pos past the end of the $, else it will not move // local_pos. - size_t parse_index(size_t *local_pos); + LIBC_INLINE size_t parse_index(size_t *local_pos) { + if (internal::isdigit(str[*local_pos])) { + auto result = internal::strtointeger(str + *local_pos, 10); + size_t index = result.value; + if (str[*local_pos + result.parsed_len] != '$') + return 0; + *local_pos = 1 + result.parsed_len + *local_pos; + return index; + } + return 0; + } // get_arg_value gets the value from the arg list at index (starting at 1). // This may require parsing the format string. An index of 0 is interpreted as @@ -89,7 +262,19 @@ class Parser { // It moves cur_args to the index requested so the appropriate value may // be read. This may involve parsing the format string, and is in the worst // case an O(n^2) operation. - void args_to_index(size_t index); + LIBC_INLINE void args_to_index(size_t index) { + if (args_index > index) { + args_index = 1; + args_cur = args_start; + } + + while (args_index < index) { + // Since all arguments must be pointers, we can just read all of them as + // void * and not worry about type issues. + args_cur.template next_var(); + ++args_index; + } + } #endif // LIBC_COPT_SCANF_DISABLE_INDEX_MODE }; diff --git a/libc/src/stdio/scanf_core/scanf_main.cpp b/libc/src/stdio/scanf_core/scanf_main.cpp index 5a79d2e624ab0..e7e41cbe899d7 100644 --- a/libc/src/stdio/scanf_core/scanf_main.cpp +++ b/libc/src/stdio/scanf_core/scanf_main.cpp @@ -21,7 +21,7 @@ namespace scanf_core { int scanf_main(Reader *reader, const char *__restrict str, internal::ArgList &args) { - Parser parser(str, args); + Parser parser(str, args); int ret_val = READ_OK; int conversions = 0; for (FormatSection cur_section = parser.get_next_section(); diff --git a/libc/test/src/stdio/printf_core/parser_test.cpp b/libc/test/src/stdio/printf_core/parser_test.cpp index 61f8c7cbe580e..910b611f51949 100644 --- a/libc/test/src/stdio/printf_core/parser_test.cpp +++ b/libc/test/src/stdio/printf_core/parser_test.cpp @@ -17,24 +17,25 @@ #include "test/UnitTest/Test.h" using __llvm_libc::cpp::string_view; +using __llvm_libc::internal::ArgList; void init(const char *__restrict str, ...) { va_list vlist; va_start(vlist, str); - __llvm_libc::internal::ArgList v(vlist); + ArgList v(vlist); va_end(vlist); - __llvm_libc::printf_core::Parser parser(str, v); + __llvm_libc::printf_core::Parser parser(str, v); } void evaluate(__llvm_libc::printf_core::FormatSection *format_arr, const char *__restrict str, ...) { va_list vlist; va_start(vlist, str); - __llvm_libc::internal::ArgList v(vlist); + ArgList v(vlist); va_end(vlist); - __llvm_libc::printf_core::Parser parser(str, v); + __llvm_libc::printf_core::Parser parser(str, v); for (auto cur_section = parser.get_next_section(); !cur_section.raw_string.empty(); diff --git a/libc/test/src/stdio/scanf_core/parser_test.cpp b/libc/test/src/stdio/scanf_core/parser_test.cpp index 2ccaf84c67552..b1f9efa0f8a2b 100644 --- a/libc/test/src/stdio/scanf_core/parser_test.cpp +++ b/libc/test/src/stdio/scanf_core/parser_test.cpp @@ -18,14 +18,15 @@ #include "test/UnitTest/Test.h" using __llvm_libc::cpp::string_view; +using __llvm_libc::internal::ArgList; void init(const char *__restrict str, ...) { va_list vlist; va_start(vlist, str); - __llvm_libc::internal::ArgList v(vlist); + ArgList v(vlist); va_end(vlist); - __llvm_libc::scanf_core::Parser parser(str, v); + __llvm_libc::scanf_core::Parser parser(str, v); } void evaluate(__llvm_libc::scanf_core::FormatSection *format_arr, @@ -35,7 +36,7 @@ void evaluate(__llvm_libc::scanf_core::FormatSection *format_arr, __llvm_libc::internal::ArgList v(vlist); va_end(vlist); - __llvm_libc::scanf_core::Parser parser(str, v); + __llvm_libc::scanf_core::Parser parser(str, v); for (auto cur_section = parser.get_next_section(); !cur_section.raw_string.empty(); diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 80ea75ecd8760..e2fa5ae34188e 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -2692,7 +2692,6 @@ libc_support_library( libc_support_library( name = "printf_parser", - srcs = ["src/stdio/printf_core/parser.cpp"], hdrs = ["src/stdio/printf_core/parser.h"], defines = PRINTF_COPTS, deps = [ @@ -2714,7 +2713,6 @@ libc_support_library( # Only used for testing. libc_support_library( name = "printf_mock_parser", - srcs = ["src/stdio/printf_core/parser.cpp"], hdrs = ["src/stdio/printf_core/parser.h"], defines = PRINTF_COPTS + ["LIBC_COPT_MOCK_ARG_LIST"], deps = [