diff options
author | Pranil Dey <mkdeyp@gmail.com> | 2024-09-30 19:03:42 +0530 |
---|---|---|
committer | Pranil Dey <mkdeyp@gmail.com> | 2024-09-30 19:03:42 +0530 |
commit | b602de4ed9f872aa2a07e8cf74d5b3c8446de221 (patch) | |
tree | 0d1fa6e4793d0a240fee8b958764cb93fc837aab /libcpp | |
parent | c16d4a0ae162abc00d97bb73e598ca00d16cf555 (diff) | |
parent | 87905f63a6521eef1f38082e2368e18c637ef092 (diff) | |
download | gcc-b602de4ed9f872aa2a07e8cf74d5b3c8446de221.zip gcc-b602de4ed9f872aa2a07e8cf74d5b3c8446de221.tar.gz gcc-b602de4ed9f872aa2a07e8cf74d5b3c8446de221.tar.bz2 |
Merge branch 'master' of git+ssh://gcc.gnu.org/git/gcc into devel/nothrow-detection
Diffstat (limited to 'libcpp')
-rw-r--r-- | libcpp/ChangeLog | 166 | ||||
-rw-r--r-- | libcpp/charset.cc | 81 | ||||
-rw-r--r-- | libcpp/config.in | 4 | ||||
-rwxr-xr-x | libcpp/configure | 4 | ||||
-rw-r--r-- | libcpp/configure.ac | 6 | ||||
-rw-r--r-- | libcpp/directives.cc | 540 | ||||
-rw-r--r-- | libcpp/expr.cc | 132 | ||||
-rw-r--r-- | libcpp/files.cc | 644 | ||||
-rw-r--r-- | libcpp/include/cpplib.h | 11 | ||||
-rw-r--r-- | libcpp/init.cc | 119 | ||||
-rw-r--r-- | libcpp/internal.h | 38 | ||||
-rw-r--r-- | libcpp/lex.cc | 265 | ||||
-rw-r--r-- | libcpp/macro.cc | 129 | ||||
-rw-r--r-- | libcpp/po/ChangeLog | 4 | ||||
-rw-r--r-- | libcpp/po/zh_CN.po | 319 |
15 files changed, 1851 insertions, 611 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index ed80d69..fb91613 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,169 @@ +2024-09-13 Jakub Jelinek <jakub@redhat.com> + + * files.cc (finish_embed): Initialize toks to tok rather + than NULL. + +2024-09-12 Jakub Jelinek <jakub@redhat.com> + + * internal.h (struct cpp_embed_params): Add base64 member. + (_cpp_free_embed_params_tokens): Declare. + * directives.cc (DIRECTIVE_TABLE): Add IN_I flag to T_EMBED. + (save_token_for_embed, _cpp_free_embed_params_tokens): New functions. + (EMBED_PARAMS): Add gnu::base64 entry. + (_cpp_parse_embed_params): Parse gnu::base64 parameter. If + -fpreprocessed without -fdirectives-only, require #embed to have + gnu::base64 parameter. Diagnose conflict between gnu::base64 and + limit or gnu::offset parameters. + (do_embed): Use _cpp_free_embed_params_tokens. + * files.cc (finish_embed, base64_dec_fn): New functions. + (base64_dec): New array. + (B64D0, B64D1, B64D2, B64D3): Define. + (finish_base64_embed): New function. + (_cpp_stack_embed): Use finish_embed. Handle params->base64 + using finish_base64_embed. + * macro.cc (builtin_has_embed): Call _cpp_free_embed_params_tokens. + +2024-09-12 Jason Merrill <jason@redhat.com> + + * include/cpplib.h (enum cpp_warning_reason): Add + CPP_W_CXX{14,17,20,23}_EXTENSIONS. + * charset.cc (_cpp_valid_ucn, convert_hex, convert_oct) + (convert_escape, narrow_str_to_charconst): Use cpp_pedwarning + instead of cpp_error for pedwarns. + * directives.cc (directive_diagnostics, _cpp_handle_directive) + (do_line, do_elif): Likewise. + * expr.cc (cpp_classify_number, eval_token): Likewise. + * lex.cc (skip_whitespace, maybe_va_opt_error) + (_cpp_lex_direct): Likewise. + * macro.cc (_cpp_arguments_ok): Likewise. + (replace_args): Use -Wvariadic-macros for pedwarn about + empty macro arguments. + +2024-09-12 Jakub Jelinek <jakub@redhat.com> + + * internal.h (struct cpp_embed_params): Add offset member. + * directives.cc (EMBED_PARAMS): Add gnu::offset entry. + (enum embed_param_kind): Add NUM_EMBED_STD_PARAMS. + (_cpp_parse_embed_params): Use NUM_EMBED_STD_PARAMS rather than + NUM_EMBED_PARAMS when parsing standard parameters. Parse gnu::offset + parameter. + * files.cc (struct _cpp_file): Add offset member. + (_cpp_stack_embed): Handle params->offset. + +2024-09-12 Jakub Jelinek <jakub@redhat.com> + + PR c/105863 + * include/cpplib.h: Implement C23 N3017 #embed - a scannable, + tooling-friendly binary resource inclusion mechanism paper. + (struct cpp_options): Add embed member. + (enum cpp_builtin_type): Add BT_HAS_EMBED. + (cpp_set_include_chains): Add another cpp_dir * argument to + the declaration. + * internal.h (enum include_type): Add IT_EMBED. + (struct cpp_reader): Add embed_include member. + (struct cpp_embed_params_tokens): New type. + (struct cpp_embed_params): New type. + (_cpp_get_token_no_padding): Declare. + (enum _cpp_find_file_kind): Add _cpp_FFK_EMBED and _cpp_FFK_HAS_EMBED. + (_cpp_stack_embed): Declare. + (_cpp_parse_expr): Change return type to cpp_num_part instead of + bool, change second argument from bool to const char * and add third + argument. + (_cpp_parse_embed_params): Declare. + * directives.cc (DIRECTIVE_TABLE): Add embed entry. + (end_directive): Don't call skip_rest_of_line for T_EMBED directive. + (_cpp_handle_directive): Return 2 rather than 1 for T_EMBED in + directives-only mode. + (parse_include): Don't Call check_eol for T_EMBED directive. + (skip_balanced_token_seq): New function. + (EMBED_PARAMS): Define. + (enum embed_param_kind): New type. + (embed_params): New variable. + (_cpp_parse_embed_params): New function. + (do_embed): New function. + (do_if): Adjust _cpp_parse_expr caller. + (do_elif): Likewise. + * expr.cc (parse_defined): Diagnose defined in #embed or __has_embed + parameters. + (_cpp_parse_expr): Change return type to cpp_num_part instead of + bool, change second argument from bool to const char * and add third + argument. Adjust function comment. For #embed/__has_embed parameters + add an artificial CPP_OPEN_PAREN. Use the second argument DIR + directly instead of string literals conditional on IS_IF. + For #embed/__has_embed parameter, stop on reaching CPP_CLOSE_PAREN + matching the artificial one. Diagnose negative or too large embed + parameter operands. + (num_binary_op): Use #embed instead of #if for diagnostics if inside + #embed/__has_embed parameter. + (num_div_op): Likewise. + * files.cc (struct _cpp_file): Add limit member and embed bitfield. + (search_cache): Add IS_EMBED argument, formatting fix. Skip over + files with different file->embed from the argument. + (find_file_in_dir): Don't call pch_open_file if file->embed. + (_cpp_find_file): Handle _cpp_FFK_EMBED and _cpp_FFK_HAS_EMBED. + (read_file_guts): Formatting fix. + (has_unique_contents): Ignore file->embed files. + (search_path_head): Handle IT_EMBED type. + (_cpp_stack_embed): New function. + (_cpp_get_file_stat): Formatting fix. + (cpp_set_include_chains): Add embed argument, save it to + pfile->embed_include and compute lens for the chain. + * init.cc (struct lang_flags): Add embed member. + (lang_defaults): Add embed initializers. + (cpp_set_lang): Initialize CPP_OPTION (pfile, embed). + (builtin_array): Add __has_embed entry. + (cpp_init_builtins): Predefine __STDC_EMBED_NOT_FOUND__, + __STDC_EMBED_FOUND__ and __STDC_EMBED_EMPTY__. + * lex.cc (cpp_directive_only_process): Handle #embed. + * macro.cc (cpp_get_token_no_padding): Rename to ... + (_cpp_get_token_no_padding): ... this. No longer static. + (builtin_has_include_1): New function. + (builtin_has_include): Use it. Use _cpp_get_token_no_padding + instead of cpp_get_token_no_padding. + (builtin_has_embed): New function. + (_cpp_builtin_macro_text): Handle BT_HAS_EMBED. + +2024-08-26 Alexander Monakov <amonakov@ispras.ru> + + * internal.h (CPP_BUFFER_PADDING): New macro; use it ... + * charset.cc (_cpp_convert_input): ...here, and ... + * files.cc (read_file_guts): ...here, and ... + * lex.cc (search_line_ssse3): here. + +2024-08-23 Alexander Monakov <amonakov@ispras.ru> + + PR preprocessor/116458 + * charset.cc (_cpp_convert_input): Bump padding to 64 if + HAVE_SSSE3. + +2024-08-22 Marc Poulhiès <poulhies@adacore.com> + + * lex.cc(search_line_ssse3): fix static_assert to use 2 arguments. + +2024-08-20 Jakub Jelinek <jakub@redhat.com> + + * init.cc (struct lang_flags): Change all members from char + typed fields to unsigned bit-fields. + (lang_defaults): Change formatting of the initializer so that it + fits to 68 columns rather than 147. + +2024-08-20 Alexander Monakov <amonakov@ispras.ru> + + * config.in: Regenerate. + * configure: Regenerate. + * configure.ac: Check for SSSE3 instead of SSE4.2. + * files.cc (read_file_guts): Bump padding to 64 if HAVE_SSSE3. + * lex.cc (search_line_acc_char): Mark inline, not "unused". + (search_line_sse2): Mark inline. + (search_line_sse42): Replace with... + (search_line_ssse3): ... this new function. Adjust the use... + (init_vectorized_lexer): ... here. Simplify. + +2024-08-06 Andi Kleen <ak@gcc.gnu.org> + + * lex.cc (search_line_mmx): Remove function. + (init_vectorized_lexer): Remove search_line_mmx. + 2024-07-25 Jakub Jelinek <jakub@redhat.com> PR c++/110343 diff --git a/libcpp/charset.cc b/libcpp/charset.cc index d58319a..32b6fd5 100644 --- a/libcpp/charset.cc +++ b/libcpp/charset.cc @@ -1633,9 +1633,11 @@ _cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr, else if ((!identifier_pos || strict) && !CPP_OPTION (pfile, delimited_escape_seqs) && CPP_OPTION (pfile, cpp_pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "named universal character escapes are only valid " - "in C++23"); + cpp_pedwarning (pfile, + CPP_OPTION (pfile, cplusplus) + ? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC, + "named universal character escapes are only " + "valid in C++23"); if (name == str) result = 0x40; else @@ -1757,8 +1759,9 @@ _cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr, "empty delimited escape sequence"); else if (!CPP_OPTION (pfile, delimited_escape_seqs) && CPP_OPTION (pfile, cpp_pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "delimited escape sequences are only valid in C++23"); + cpp_pedwarning (pfile, (CPP_OPTION (pfile, cplusplus) + ? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC), + "delimited escape sequences are only valid in C++23"); str++; length = 0; delimited = false; @@ -2129,10 +2132,11 @@ convert_hex (cpp_reader *pfile, const uchar *from, const uchar *limit, "empty delimited escape sequence"); return from; } - else if (!CPP_OPTION (pfile, delimited_escape_seqs) - && CPP_OPTION (pfile, cpp_pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "delimited escape sequences are only valid in C++23"); + else if (!CPP_OPTION (pfile, delimited_escape_seqs) + && CPP_OPTION (pfile, cpp_pedantic)) + cpp_pedwarning (pfile, (CPP_OPTION (pfile, cplusplus) + ? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC), + "delimited escape sequences are only valid in C++23"); delimited = false; extend_char_range (&char_range, loc_reader); } @@ -2234,8 +2238,10 @@ convert_oct (cpp_reader *pfile, const uchar *from, const uchar *limit, } else if (!CPP_OPTION (pfile, delimited_escape_seqs) && CPP_OPTION (pfile, cpp_pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "delimited escape sequences are only valid in C++23"); + cpp_pedwarning (pfile, (CPP_OPTION (pfile, cplusplus) + ? CPP_W_CXX23_EXTENSIONS : CPP_W_PEDANTIC), + "delimited escape sequences are only valid " + "in C++23"); extend_char_range (&char_range, loc_reader); } else @@ -2300,20 +2306,20 @@ convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit, char_range, loc_reader, ranges); case 'x': - if (uneval && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "numeric escape sequence in unevaluated string: " - "'\\%c'", (int) c); + if (uneval) + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "numeric escape sequence in unevaluated string: " + "'\\%c'", (int) c); return convert_hex (pfile, from, limit, tbuf, cvt, char_range, loc_reader, ranges); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case 'o': - if (uneval && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "numeric escape sequence in unevaluated string: " - "'\\%c'", (int) c); + if (uneval) + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "numeric escape sequence in unevaluated string: " + "'\\%c'", (int) c); return convert_oct (pfile, from, limit, tbuf, cvt, char_range, loc_reader, ranges); @@ -2345,9 +2351,8 @@ convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit, break; case 'e': case 'E': - if (CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, - "non-ISO-standard escape sequence, '\\%c'", (int) c); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "non-ISO-standard escape sequence, '\\%c'", (int) c); c = charconsts[2]; break; @@ -2757,7 +2762,7 @@ narrow_str_to_charconst (cpp_reader *pfile, cpp_string str, if (type == CPP_UTF8CHAR) max_chars = 1; - else if (i > 1 && CPP_OPTION (pfile, cplusplus) && CPP_PEDANTIC (pfile)) + else if (i > 1 && CPP_OPTION (pfile, cplusplus)) { /* C++ as a DR since P1854R4 - Making non-encodable string literals ill-formed @@ -2773,15 +2778,15 @@ narrow_str_to_charconst (cpp_reader *pfile, cpp_string str, { if (src_chars <= 2) diagnosed - = cpp_error (pfile, CPP_DL_PEDWARN, - "character not encodable in a single execution " - "character code unit"); + = cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "character not encodable in a single " + "execution character code unit"); else diagnosed - = cpp_error (pfile, CPP_DL_PEDWARN, - "at least one character in a multi-character " - "literal not encodable in a single execution " - "character code unit"); + = cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "at least one character in a multi-" + "character literal not encodable in a " + "single execution character code unit"); if (diagnosed && i > max_chars) i = max_chars; } @@ -3093,6 +3098,7 @@ _cpp_convert_input (cpp_reader *pfile, const char *input_charset, struct cset_converter input_cset; struct _cpp_strbuf to; unsigned char *buffer; + size_t pad = CPP_BUFFER_PADDING; input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset); if (input_cset.func == convert_no_conversion) @@ -3130,15 +3136,12 @@ _cpp_convert_input (cpp_reader *pfile, const char *input_charset, } /* Resize buffer if we allocated substantially too much, or if we - haven't enough space for the \n-terminator or following - 15 bytes of padding (used to quiet warnings from valgrind or - Address Sanitizer, when the optimized lexer accesses aligned - 16-byte memory chunks, including the bytes after the malloced, - area, and stops lexing on '\n'). */ - if (to.len + 4096 < to.asize || to.len + 16 > to.asize) - to.text = XRESIZEVEC (uchar, to.text, to.len + 16); - - memset (to.text + to.len, '\0', 16); + don't have enough space for the following padding, which allows + search_line_fast to use (possibly misaligned) vector loads. */ + if (to.len + 4096 < to.asize || to.len + pad > to.asize) + to.text = XRESIZEVEC (uchar, to.text, to.len + pad); + + memset (to.text + to.len, '\0', pad); /* If the file is using old-school Mac line endings (\r only), terminate with another \r, not an \n, so that we do not mistake diff --git a/libcpp/config.in b/libcpp/config.in index 253ef03..b2e2f4e8 100644 --- a/libcpp/config.in +++ b/libcpp/config.in @@ -210,8 +210,8 @@ /* Define to 1 if you have the `putc_unlocked' function. */ #undef HAVE_PUTC_UNLOCKED -/* Define to 1 if you can assemble SSE4 insns. */ -#undef HAVE_SSE4 +/* Define to 1 if you can assemble SSSE3 insns. */ +#undef HAVE_SSSE3 /* Define to 1 if you have the <stddef.h> header file. */ #undef HAVE_STDDEF_H diff --git a/libcpp/configure b/libcpp/configure index 32d6aaa..1391081 100755 --- a/libcpp/configure +++ b/libcpp/configure @@ -9140,14 +9140,14 @@ case $target in int main () { -asm ("pcmpestri %0, %%xmm0, %%xmm1" : : "i"(0)) +asm ("pshufb %xmm0, %xmm1") ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : -$as_echo "#define HAVE_SSE4 1" >>confdefs.h +$as_echo "#define HAVE_SSSE3 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext diff --git a/libcpp/configure.ac b/libcpp/configure.ac index b883fec..981f97c4 100644 --- a/libcpp/configure.ac +++ b/libcpp/configure.ac @@ -197,9 +197,9 @@ fi case $target in i?86-* | x86_64-*) - AC_TRY_COMPILE([], [asm ("pcmpestri %0, %%xmm0, %%xmm1" : : "i"(0))], - [AC_DEFINE([HAVE_SSE4], [1], - [Define to 1 if you can assemble SSE4 insns.])]) + AC_TRY_COMPILE([], [asm ("pshufb %xmm0, %xmm1")], + [AC_DEFINE([HAVE_SSSE3], [1], + [Define to 1 if you can assemble SSSE3 insns.])]) esac # Enable --enable-host-shared. diff --git a/libcpp/directives.cc b/libcpp/directives.cc index 479f8c7..866ac9a 100644 --- a/libcpp/directives.cc +++ b/libcpp/directives.cc @@ -159,6 +159,7 @@ static void cpp_pop_definition (cpp_reader *, struct def_pragma_macro *); D(error, T_ERROR, STDC89, 0) \ D(pragma, T_PRAGMA, STDC89, IN_I) \ D(warning, T_WARNING, STDC23, 0) \ + D(embed, T_EMBED, STDC23, IN_I | INCL | EXPAND) \ D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND) \ D(ident, T_IDENT, EXTENSION, IN_I) \ D(import, T_IMPORT, EXTENSION, INCL | EXPAND) /* ObjC */ \ @@ -326,7 +327,8 @@ end_directive (cpp_reader *pfile, int skip_line) /* We don't skip for an assembler #. */ else if (skip_line) { - skip_rest_of_line (pfile); + if (pfile->directive != &dtable[T_EMBED]) + skip_rest_of_line (pfile); if (!pfile->keep_tokens) { pfile->cur_run = &pfile->base_run; @@ -381,28 +383,37 @@ directive_diagnostics (cpp_reader *pfile, const directive *dir, int indented) -pedantic take precedence if both are applicable. */ if (! pfile->state.skipping) { + bool warned = false; if (dir->origin == EXTENSION - && !(dir == &dtable[T_IMPORT] && CPP_OPTION (pfile, objc)) - && CPP_PEDANTIC (pfile)) - cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name); - else if (dir == &dtable[T_WARNING]) + && !(dir == &dtable[T_IMPORT] && CPP_OPTION (pfile, objc))) + warned + = cpp_pedwarning (pfile, CPP_W_PEDANTIC, "#%s is a GCC extension", + dir->name); + if (!warned && dir == &dtable[T_WARNING]) { if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, warning_directive)) { if (CPP_OPTION (pfile, cplusplus)) - cpp_error (pfile, CPP_DL_PEDWARN, - "#%s before C++23 is a GCC extension", dir->name); + warned + = cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS, + "#%s before C++23 is a GCC extension", + dir->name); else - cpp_error (pfile, CPP_DL_PEDWARN, - "#%s before C23 is a GCC extension", dir->name); + warned + = cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "#%s before C23 is a GCC extension", + dir->name); } - else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0) - cpp_warning (pfile, CPP_W_C11_C23_COMPAT, - "#%s before C23 is a GCC extension", dir->name); + + if (!warned && CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0) + warned = cpp_warning (pfile, CPP_W_C11_C23_COMPAT, + "#%s before C23 is a GCC extension", + dir->name); } - else if (((dir->flags & DEPRECATED) != 0 - || (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc))) - && CPP_OPTION (pfile, cpp_warn_deprecated)) + + if (((dir->flags & DEPRECATED) != 0 + || (dir == &dtable[T_IMPORT] && !CPP_OPTION (pfile, objc))) + && !warned) cpp_warning (pfile, CPP_W_DEPRECATED, "#%s is a deprecated GCC extension", dir->name); } @@ -448,9 +459,9 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented) if (was_parsing_args) { - if (CPP_OPTION (pfile, cpp_pedantic)) - cpp_error (pfile, CPP_DL_PEDWARN, - "embedding a directive within macro arguments is not portable"); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "embedding a directive within macro arguments is not " + "portable"); pfile->state.parsing_args = 0; pfile->state.prevent_expansion = 0; } @@ -475,10 +486,10 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented) else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM) { dir = &linemarker_dir; - if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed) + if (! CPP_OPTION (pfile, preprocessed) && ! pfile->state.skipping) - cpp_error (pfile, CPP_DL_PEDWARN, - "style of line directive is a GCC extension"); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "style of line directive is a GCC extension"); } if (dir) @@ -569,7 +580,15 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented) prepare_directive_trad (pfile); if (dir) - pfile->directive->handler (pfile); + { + pfile->directive->handler (pfile); + if (pfile->directive == &dtable[T_EMBED] + && skip + && CPP_OPTION (pfile, directives_only)) + /* Signal to cpp_directive_only_process it needs to emit + the #embed expansion. */ + skip = 2; + } else if (skip == 0) _cpp_backup_tokens (pfile, 1); @@ -821,9 +840,10 @@ parse_include (cpp_reader *pfile, int *pangle_brackets, return NULL; } - if (pfile->directive == &dtable[T_PRAGMA]) + if (pfile->directive == &dtable[T_PRAGMA] + || pfile->directive == &dtable[T_EMBED]) { - /* This pragma allows extra tokens after the file name. */ + /* This pragma or #embed allows extra tokens after the file name. */ } else if (buf == NULL || CPP_OPTION (pfile, discard_comments)) check_eol (pfile, true); @@ -921,6 +941,445 @@ do_include_next (cpp_reader *pfile) do_include_common (pfile, type); } +/* Helper function for skip_balanced_token_seq and _cpp_parse_embed_params. + Save one token *TOKEN into *SAVE. */ + +static void +save_token_for_embed (cpp_embed_params_tokens *save, const cpp_token *token) +{ + if (save->count == 0) + { + _cpp_init_tokenrun (&save->base_run, 4); + save->cur_run = &save->base_run; + save->cur_token = save->base_run.base; + } + else if (save->cur_token == save->cur_run->limit) + { + save->cur_run->next = XNEW (tokenrun); + save->cur_run->next->prev = save->cur_run; + _cpp_init_tokenrun (save->cur_run->next, 4); + save->cur_run = save->cur_run->next; + save->cur_token = save->cur_run->base; + } + *save->cur_token = *token; + save->cur_token->flags |= NO_EXPAND; + save->cur_token++; + save->count++; +} + +/* Free memory associated with saved tokens in *SAVE. */ + +void +_cpp_free_embed_params_tokens (cpp_embed_params_tokens *save) +{ + if (save->count == 0) + return; + tokenrun *n; + for (tokenrun *t = &save->base_run; t; t = n) + { + n = t->next; + XDELETEVEC (t->base); + if (t != &save->base_run) + XDELETE (t); + } + save->count = 0; +} + +/* Skip over balanced preprocessing tokens until END is found. + If SAVE is non-NULL, remember the parsed tokens in it. NESTED is + false in the outermost invocation of the function and true + when called recursively. */ + +static void +skip_balanced_token_seq (cpp_reader *pfile, cpp_ttype end, + cpp_embed_params_tokens *save, bool nested) +{ + do + { + const cpp_token *token = cpp_peek_token (pfile, 0); + if (token->type == CPP_EOF) + { + char c = 0; + switch (end) + { + case CPP_CLOSE_PAREN: c = '('; break; + case CPP_CLOSE_SQUARE: c = '['; break; + case CPP_CLOSE_BRACE: c = '{'; break; + default: abort (); + } + cpp_error (pfile, CPP_DL_ERROR, "unbalanced '%c'", c); + return; + } + token = cpp_get_token (pfile); + if (save + && (token->type != CPP_PADDING || save->count) + && (token->type != end || nested)) + save_token_for_embed (save, token); + if (token->type == end) + return; + switch (token->type) + { + case CPP_OPEN_PAREN: + skip_balanced_token_seq (pfile, CPP_CLOSE_PAREN, save, true); + break; + case CPP_OPEN_SQUARE: + skip_balanced_token_seq (pfile, CPP_CLOSE_SQUARE, save, true); + break; + case CPP_OPEN_BRACE: + skip_balanced_token_seq (pfile, CPP_CLOSE_BRACE, save, true); + break; + case CPP_CLOSE_PAREN: + cpp_error (pfile, CPP_DL_ERROR, "unbalanced '%c'", ')'); + break; + case CPP_CLOSE_SQUARE: + cpp_error (pfile, CPP_DL_ERROR, "unbalanced '%c'", ']'); + break; + case CPP_CLOSE_BRACE: + cpp_error (pfile, CPP_DL_ERROR, "unbalanced '%c'", '}'); + break; + default: + break; + } + } + while (1); +} + +#define EMBED_PARAMS \ + EMBED_PARAM (LIMIT, "limit") \ + EMBED_PARAM (PREFIX, "prefix") \ + EMBED_PARAM (SUFFIX, "suffix") \ + EMBED_PARAM (IF_EMPTY, "if_empty") \ + EMBED_PARAM (GNU_BASE64, "base64") \ + EMBED_PARAM (GNU_OFFSET, "offset") + +enum embed_param_kind { +#define EMBED_PARAM(c, s) EMBED_PARAM_##c, + EMBED_PARAMS +#undef EMBED_PARAM + NUM_EMBED_PARAMS, + NUM_EMBED_STD_PARAMS = EMBED_PARAM_IF_EMPTY + 1 +}; + +static struct { int len; const char *name; } embed_params[NUM_EMBED_PARAMS] = { +#define EMBED_PARAM(c, s) { sizeof (s) - 1, s }, + EMBED_PARAMS +#undef EMBED_PARAM +}; + +/* Parse parameters of #embed directive or __has_embed expression. + Fills in details about parsed parameters in *PARAMS. + Returns true if all the parameters have been successfully parsed, + false on errors. */ + +bool +_cpp_parse_embed_params (cpp_reader *pfile, struct cpp_embed_params *params) +{ + const cpp_token *token = _cpp_get_token_no_padding (pfile); + bool ret = true; + int seen = 0; + params->limit = -1; + do + { + const unsigned char *param_name = NULL; + const unsigned char *param_prefix = NULL; + int param_name_len = 0, param_prefix_len = 0; + bool has_scope = false; + if (token->type != CPP_NAME) + { + if (token->type == CPP_EOF) + { + if (params->has_embed) + { + cpp_error (pfile, CPP_DL_ERROR, "expected ')'"); + return false; + } + } + else if (token->type != CPP_CLOSE_PAREN || !params->has_embed) + { + cpp_error (pfile, CPP_DL_ERROR, "expected parameter name"); + return false; + } + if (params->base64.count + && (seen & ((1 << EMBED_PARAM_LIMIT) + | (1 << EMBED_PARAM_GNU_OFFSET))) != 0) + { + ret = false; + if (!params->has_embed) + cpp_error_with_line (pfile, CPP_DL_ERROR, + params->base64.base_run.base->src_loc, 0, + "'gnu::base64' parameter conflicts with " + "'limit' or 'gnu::offset' parameters"); + } + else if (params->base64.count == 0 + && CPP_OPTION (pfile, preprocessed)) + { + ret = false; + if (!params->has_embed) + cpp_error_with_line (pfile, CPP_DL_ERROR, params->loc, 0, + "'gnu::base64' parameter required in " + "preprocessed source"); + } + return ret; + } + param_name = NODE_NAME (token->val.node.spelling); + param_name_len = NODE_LEN (token->val.node.spelling); + location_t loc = token->src_loc; + token = _cpp_get_token_no_padding (pfile); + if (token->type == CPP_SCOPE) + { + has_scope = true; + token = _cpp_get_token_no_padding (pfile); + } + else if (token->type == CPP_COLON + && (token->flags & COLON_SCOPE) != 0) + { + has_scope = true; + token = _cpp_get_token_no_padding (pfile); + if (token->type != CPP_COLON) + { + cpp_error (pfile, CPP_DL_ERROR, "expected ':'"); + return false; + } + token = _cpp_get_token_no_padding (pfile); + } + if (has_scope) + { + if (token->type != CPP_NAME) + { + cpp_error (pfile, CPP_DL_ERROR, "expected parameter name"); + return false; + } + param_prefix = param_name; + param_prefix_len = param_name_len; + param_name = NODE_NAME (token->val.node.spelling); + param_name_len = NODE_LEN (token->val.node.spelling); + loc = token->src_loc; + token = _cpp_get_token_no_padding (pfile); + } + if (param_name_len > 4 + && param_name[0] == '_' + && param_name[1] == '_' + && param_name[param_name_len - 1] == '_' + && param_name[param_name_len - 2] == '_') + { + param_name += 2; + param_name_len -= 4; + } + if (param_prefix + && param_prefix_len > 4 + && param_prefix[0] == '_' + && param_prefix[1] == '_' + && param_prefix[param_prefix_len - 1] == '_' + && param_prefix[param_prefix_len - 2] == '_') + { + param_prefix += 2; + param_prefix_len -= 4; + } + size_t param_kind = -1; + if (param_prefix == NULL) + { + for (size_t i = 0; i < NUM_EMBED_STD_PARAMS; ++i) + if (param_name_len == embed_params[i].len + && memcmp (param_name, embed_params[i].name, + param_name_len) == 0) + { + param_kind = i; + break; + } + } + else if (param_prefix_len == 3 && memcmp (param_prefix, "gnu", 3) == 0) + { + for (size_t i = NUM_EMBED_STD_PARAMS; i < NUM_EMBED_PARAMS; ++i) + if (param_name_len == embed_params[i].len + && memcmp (param_name, embed_params[i].name, + param_name_len) == 0) + { + param_kind = i; + break; + } + } + if (param_kind != (size_t) -1) + { + if ((seen & (1 << param_kind)) == 0) + seen |= 1 << param_kind; + else + cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, + "duplicate embed parameter '%.*s%s%.*s'", + param_prefix_len, + param_prefix + ? (const char *) param_prefix : "", + param_prefix ? "::" : "", + param_name_len, param_name); + } + else + { + ret = false; + if (!params->has_embed) + cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, + "unknown embed parameter '%.*s%s%.*s'", + param_prefix_len, + param_prefix + ? (const char *) param_prefix : "", + param_prefix ? "::" : "", + param_name_len, param_name); + } + if (param_kind != (size_t) -1 && token->type != CPP_OPEN_PAREN) + cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, + "expected '('"); + else if (param_kind == EMBED_PARAM_LIMIT + || param_kind == EMBED_PARAM_GNU_OFFSET) + { + if (params->has_embed && pfile->op_stack == NULL) + _cpp_expand_op_stack (pfile); + cpp_num_part res = _cpp_parse_expr (pfile, "#embed", token); + if (param_kind == EMBED_PARAM_LIMIT) + params->limit = res; + else + { + if (res > INTTYPE_MAXIMUM (off_t)) + cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, + "too large 'gnu::offset' argument"); + else + params->offset = res; + } + token = _cpp_get_token_no_padding (pfile); + } + else if (param_kind == EMBED_PARAM_GNU_BASE64) + { + token = _cpp_get_token_no_padding (pfile); + while (token->type == CPP_OTHER + && CPP_OPTION (pfile, preprocessed) + && !CPP_OPTION (pfile, directives_only) + && token->val.str.len == 1 + && token->val.str.text[0] == '\\') + { + /* Allow backslash newline inside of gnu::base64 argument + for -fpreprocessed, so that it doesn't have to be + megabytes long line. */ + pfile->state.in_directive = 0; + token = _cpp_get_token_no_padding (pfile); + pfile->state.in_directive = 3; + } + if (token->type == CPP_STRING) + { + do + { + save_token_for_embed (¶ms->base64, token); + token = _cpp_get_token_no_padding (pfile); + while (token->type == CPP_OTHER + && CPP_OPTION (pfile, preprocessed) + && !CPP_OPTION (pfile, directives_only) + && token->val.str.len == 1 + && token->val.str.text[0] == '\\') + { + pfile->state.in_directive = 0; + token = _cpp_get_token_no_padding (pfile); + pfile->state.in_directive = 3; + } + } + while (token->type == CPP_STRING); + if (token->type != CPP_CLOSE_PAREN) + cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, 0, + "expected ')'"); + } + else + { + cpp_error_with_line (pfile, CPP_DL_ERROR, token->src_loc, 0, + "expected character string literal"); + if (token->type != CPP_CLOSE_PAREN) + token = _cpp_get_token_no_padding (pfile); + } + token = _cpp_get_token_no_padding (pfile); + } + else if (token->type == CPP_OPEN_PAREN) + { + cpp_embed_params_tokens *save = NULL; + auto save_comments = pfile->state.save_comments; + switch (param_kind) + { + case EMBED_PARAM_PREFIX: save = ¶ms->prefix; break; + case EMBED_PARAM_SUFFIX: save = ¶ms->suffix; break; + case EMBED_PARAM_IF_EMPTY: save = ¶ms->if_empty; break; + default: break; + } + if (params->has_embed) + save = NULL; + else if (save) + pfile->state.save_comments = !CPP_OPTION (pfile, discard_comments); + skip_balanced_token_seq (pfile, CPP_CLOSE_PAREN, save, false); + pfile->state.save_comments = save_comments; + token = _cpp_get_token_no_padding (pfile); + } + } + while (1); +} + +/* Handle #embed directive. */ + +static void +do_embed (cpp_reader *pfile) +{ + int angle_brackets; + struct cpp_embed_params params = {}; + bool ok; + const char *fname = NULL; + + /* Tell the lexer this is an embed directive. */ + pfile->state.in_directive = 3; + + if (CPP_OPTION (pfile, traditional)) + { + cpp_error (pfile, CPP_DL_ERROR, /* FIXME should be DL_SORRY */ + "#embed not supported in traditional C"); + skip_rest_of_line (pfile); + goto done; + } + + if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, embed)) + { + if (CPP_OPTION (pfile, cplusplus)) + cpp_error (pfile, CPP_DL_PEDWARN, + "#%s is a GCC extension", "embed"); + else + cpp_error (pfile, CPP_DL_PEDWARN, + "#%s before C23 is a GCC extension", "embed"); + } + + fname = parse_include (pfile, &angle_brackets, NULL, ¶ms.loc); + if (!fname) + { + skip_rest_of_line (pfile); + goto done; + } + + if (!*fname) + { + cpp_error_with_line (pfile, CPP_DL_ERROR, params.loc, 0, + "empty filename in #%s", + pfile->directive->name); + skip_rest_of_line (pfile); + goto done; + } + + pfile->state.angled_headers = false; + pfile->state.directive_wants_padding = false; + ok = _cpp_parse_embed_params (pfile, ¶ms); + + /* Get out of macro context, if we are. */ + skip_rest_of_line (pfile); + + if (ok) + _cpp_stack_embed (pfile, fname, angle_brackets, ¶ms); + + _cpp_free_embed_params_tokens (¶ms.prefix); + _cpp_free_embed_params_tokens (¶ms.suffix); + _cpp_free_embed_params_tokens (¶ms.if_empty); + _cpp_free_embed_params_tokens (¶ms.base64); + + done: + XDELETEVEC (fname); +} + /* Subroutine of do_linemarker. Read possible flags after file name. LAST is the last flag seen; 0 if this is the first flag. Return the flag if it is valid, 0 at the end of the directive. Otherwise @@ -1016,8 +1475,9 @@ do_line (cpp_reader *pfile) return; } - if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap || wrapped)) - cpp_error (pfile, CPP_DL_PEDWARN, "line number out of range"); + if ((new_lineno == 0 || new_lineno > cap || wrapped) + && cpp_pedwarning (pfile, CPP_W_PEDANTIC, "line number out of range")) + ; else if (wrapped) cpp_error (pfile, CPP_DL_WARNING, "line number out of range"); @@ -2084,7 +2544,7 @@ do_if (cpp_reader *pfile) int skip = 1; if (! pfile->state.skipping) - skip = _cpp_parse_expr (pfile, true) == false; + skip = _cpp_parse_expr (pfile, "#if", NULL) == false; push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro); } @@ -2159,20 +2619,20 @@ do_elif (cpp_reader *pfile) && !pfile->state.skipping) { if (CPP_OPTION (pfile, cplusplus)) - cpp_error (pfile, CPP_DL_PEDWARN, - "#%s before C++23 is a GCC extension", - pfile->directive->name); + cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS, + "#%s before C++23 is a GCC extension", + pfile->directive->name); else - cpp_error (pfile, CPP_DL_PEDWARN, - "#%s before C23 is a GCC extension", - pfile->directive->name); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "#%s before C23 is a GCC extension", + pfile->directive->name); } pfile->state.skipping = 1; } else { if (pfile->directive == &dtable[T_ELIF]) - pfile->state.skipping = !_cpp_parse_expr (pfile, false); + pfile->state.skipping = !_cpp_parse_expr (pfile, "#elif", NULL); else { cpp_hashnode *node = lex_macro_node (pfile, false); @@ -2198,13 +2658,13 @@ do_elif (cpp_reader *pfile) && pfile->state.skipping != skip) { if (CPP_OPTION (pfile, cplusplus)) - cpp_error (pfile, CPP_DL_PEDWARN, - "#%s before C++23 is a GCC extension", - pfile->directive->name); + cpp_pedwarning (pfile, CPP_W_CXX23_EXTENSIONS, + "#%s before C++23 is a GCC extension", + pfile->directive->name); else - cpp_error (pfile, CPP_DL_PEDWARN, - "#%s before C23 is a GCC extension", - pfile->directive->name); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "#%s before C23 is a GCC extension", + pfile->directive->name); } pfile->state.skipping = skip; } diff --git a/libcpp/expr.cc b/libcpp/expr.cc index 815eb13..089bf3e 100644 --- a/libcpp/expr.cc +++ b/libcpp/expr.cc @@ -662,9 +662,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, if (radix == 8) radix = 10; - if (CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "fixed-point constants are a GCC extension"); + cpp_pedwarning_with_line + (pfile, CPP_W_PEDANTIC, virtual_location, 0, + "fixed-point constants are a GCC extension"); goto syntax_ok; } else @@ -701,11 +701,13 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, && !CPP_OPTION (pfile, extended_numbers)) { if (CPP_OPTION (pfile, cplusplus)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "use of C++17 hexadecimal floating constant"); + cpp_pedwarning_with_line (pfile, CPP_W_CXX17_EXTENSIONS, + virtual_location, 0, "use of C++17 " + "hexadecimal floating constant"); else - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "use of C99 hexadecimal floating constant"); + cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, + virtual_location, 0, "use of C99 " + "hexadecimal floating constant"); } if (float_flag == AFTER_EXPON) @@ -766,9 +768,10 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, /* A suffix for double is a GCC extension via decimal float support. If the suffix also specifies an imaginary value we'll catch that later. */ - if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "suffix for double constant is a GCC extension"); + if (result == CPP_N_MEDIUM) + cpp_pedwarning_with_line + (pfile, CPP_W_PEDANTIC, virtual_location, 0, + "suffix for double constant is a GCC extension"); /* Radix must be 10 for decimal floats. */ if ((result & CPP_N_DFLOAT) && radix != 10) @@ -779,15 +782,16 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, return CPP_N_INVALID; } - if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "fixed-point constants are a GCC extension"); + if (result & (CPP_N_FRACT | CPP_N_ACCUM)) + cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, virtual_location, 0, + "fixed-point constants are a GCC extension"); if (result & CPP_N_DFLOAT) { - if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, dfp_constants)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "decimal float constants are a C23 feature"); + if (!CPP_OPTION (pfile, dfp_constants)) + cpp_pedwarning_with_line + (pfile, CPP_W_PEDANTIC, virtual_location, 0, + "decimal float constants are a C23 feature"); else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0) cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT, virtual_location, 0, @@ -870,12 +874,12 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT, virtual_location, 0, message); } - else if (CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, true_false)) + else if (!CPP_OPTION (pfile, true_false)) { const char *message = N_("ISO C does not support literal " "%<wb%> suffixes before C23"); - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - message); + cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, + virtual_location, 0, message); } } @@ -883,20 +887,27 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, } syntax_ok: - if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - "imaginary constants are a GCC extension"); + if (result & CPP_N_IMAGINARY) + cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, virtual_location, 0, + "imaginary constants are a GCC extension"); if (radix == 2) { + bool warned = false; if (!CPP_OPTION (pfile, binary_constants) && CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0, - CPP_OPTION (pfile, cplusplus) - ? N_("binary constants are a C++14 feature " - "or GCC extension") - : N_("binary constants are a C23 feature " - "or GCC extension")); - else if (CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0) + { + if (CPP_OPTION (pfile, cplusplus)) + warned + = (cpp_pedwarning_with_line + (pfile, CPP_W_CXX14_EXTENSIONS, virtual_location, 0, + "binary constants are a C++14 feature or GCC extension")); + else + warned + = (cpp_pedwarning_with_line + (pfile, CPP_W_PEDANTIC, virtual_location, 0, + "binary constants are a C23 feature or GCC extension")); + } + if (!warned && CPP_OPTION (pfile, cpp_warn_c11_c23_compat) > 0) cpp_warning_with_line (pfile, CPP_W_C11_C23_COMPAT, virtual_location, 0, "binary constants are a C23 feature"); @@ -1106,6 +1117,9 @@ parse_defined (cpp_reader *pfile) const cpp_token *token; cpp_context *initial_context = pfile->context; + if (pfile->state.in_directive == 3) + cpp_error (pfile, CPP_DL_ERROR, "'defined' in #embed parameter"); + /* Don't expand macros. */ pfile->state.prevent_expansion++; @@ -1264,10 +1278,10 @@ eval_token (cpp_reader *pfile, const cpp_token *token, { /* A pedantic warning takes precedence over a deprecated warning here. */ - if (CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, - virtual_location, 0, - "assertions are a GCC extension"); + if (cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, + virtual_location, 0, + "assertions are a GCC extension")) + ; else if (CPP_OPTION (pfile, cpp_warn_deprecated)) cpp_warning_with_line (pfile, CPP_W_DEPRECATED, virtual_location, 0, "assertions are a deprecated extension"); @@ -1356,7 +1370,9 @@ static const struct cpp_operator }; /* Parse and evaluate a C expression, reading from PFILE. - Returns the truth value of the expression. + Returns the truth value of the expression if OPEN_PAREN + is NULL, otherwise the low 64-bits of the result (when parsing + #embed/__has_embed parameters). The implementation is an operator precedence parser, i.e. a bottom-up parser, using a stack for not-yet-reduced tokens. @@ -1366,8 +1382,9 @@ static const struct cpp_operator recently pushed operator is 'top->op'. An operand (value) is stored in the 'value' field of the stack element of the operator that precedes it. */ -bool -_cpp_parse_expr (cpp_reader *pfile, bool is_if) +cpp_num_part +_cpp_parse_expr (cpp_reader *pfile, const char *dir, + const cpp_token *open_paren) { struct op *top = pfile->op_stack; unsigned int lex_count; @@ -1384,6 +1401,14 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) /* Lowest priority operator prevents further reductions. */ top->op = CPP_EOF; + if (pfile->state.in_directive == 3) + { + ++top; + top->op = CPP_OPEN_PAREN; + top->token = open_paren; + top->loc = open_paren->src_loc; + } + for (;;) { struct op op; @@ -1454,7 +1479,7 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) if (op.op == CPP_EOF && top->op == CPP_EOF) SYNTAX_ERROR2_AT (op.loc, - "%s with no expression", is_if ? "#if" : "#elif"); + "%s with no expression", dir); if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) SYNTAX_ERROR2_AT (op.loc, @@ -1478,6 +1503,8 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) switch (op.op) { case CPP_CLOSE_PAREN: + if (pfile->state.in_directive == 3 && top == pfile->op_stack) + goto embed_done; continue; case CPP_OR_OR: if (!num_zerop (top->value)) @@ -1520,12 +1547,31 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if) if (top != pfile->op_stack) { cpp_error_with_line (pfile, CPP_DL_ICE, top->loc, 0, - "unbalanced stack in %s", - is_if ? "#if" : "#elif"); + "unbalanced stack in %s", dir); syntax_error: return false; /* Return false on syntax error. */ } + if (pfile->state.in_directive == 3) + { + embed_done: + if (num_zerop (top->value)) + return 0; + if (!top->value.unsignedp + && !num_positive (top->value, CPP_OPTION (pfile, precision))) + { + cpp_error_with_line (pfile, CPP_DL_ERROR, top->loc, 0, + "negative embed parameter operand"); + return 1; + } + if (top->value.high) + { + cpp_error_with_line (pfile, CPP_DL_ERROR, top->loc, 0, + "too large embed parameter operand"); + return 1; + } + return top->value.low; + } return !num_zerop (top->value); } @@ -2079,7 +2125,9 @@ num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99) || !pfile->state.skip_eval)) cpp_pedwarning (pfile, CPP_W_PEDANTIC, - "comma operator in operand of #if"); + "comma operator in operand of #%s", + pfile->state.in_directive == 3 + ? "embed" : "if"); lhs = rhs; break; } @@ -2215,7 +2263,9 @@ num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op, { if (!pfile->state.skip_eval) cpp_error_with_line (pfile, CPP_DL_ERROR, location, 0, - "division by zero in #if"); + "division by zero in #%s", + pfile->state.in_directive == 3 + ? "embed" : "if"); lhs.unsignedp = unsignedp; return lhs; } diff --git a/libcpp/files.cc b/libcpp/files.cc index 78f56e3..0311699 100644 --- a/libcpp/files.cc +++ b/libcpp/files.cc @@ -87,6 +87,12 @@ struct _cpp_file /* As filled in by stat(2) for the file. */ struct stat st; + /* Size for #embed, perhaps smaller than st.st_size. */ + size_t limit; + + /* Offset for #embed. */ + off_t offset; + /* File descriptor. Invalid if -1, otherwise open. */ int fd; @@ -113,6 +119,9 @@ struct _cpp_file and error should be emitted if it is included normally. */ bool deferred_error : 1; + /* File loaded from #embed. */ + bool embed : 1; + /* > 0: Known C++ Module header unit, <0: known not. ==0, unknown */ int header_unit : 2; }; @@ -187,7 +196,8 @@ static const char *dir_name_of_file (_cpp_file *file); static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int, location_t); static struct cpp_file_hash_entry *search_cache (struct cpp_file_hash_entry *head, - const cpp_dir *start_dir); + const cpp_dir *start_dir, + bool is_embed); static _cpp_file *make_cpp_file (cpp_dir *, const char *fname); static void destroy_cpp_file (_cpp_file *); static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp); @@ -425,7 +435,7 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch, } file->path = path; - if (pch_open_file (pfile, file, invalid_pch)) + if (!file->embed && pch_open_file (pfile, file, invalid_pch)) return true; if (open_file (file)) @@ -514,7 +524,9 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool invalid_pch = false; bool saw_bracket_include = false; bool saw_quote_include = false; + bool saw_embed_include = false; struct cpp_dir *found_in_cache = NULL; + bool is_embed = kind == _cpp_FFK_EMBED || kind == _cpp_FFK_HAS_EMBED; /* Ensure we get no confusion between cached files and directories. */ if (start_dir == NULL) @@ -526,10 +538,12 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, /* First check the cache before we resort to memory allocation. */ cpp_file_hash_entry *entry - = search_cache ((struct cpp_file_hash_entry *) *hash_slot, start_dir); + = search_cache ((struct cpp_file_hash_entry *) *hash_slot, start_dir, + is_embed); if (entry) { - if (entry->u.file->deferred_error && kind == _cpp_FFK_NORMAL) + if (entry->u.file->deferred_error + && (kind == _cpp_FFK_NORMAL || kind == _cpp_FFK_EMBED)) { open_file_failed (pfile, entry->u.file, angle_brackets, loc); entry->u.file->deferred_error = false; @@ -541,6 +555,7 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, file->implicit_preinclude = (kind == _cpp_FFK_PRE_INCLUDE || (pfile->buffer && pfile->buffer->file->implicit_preinclude)); + file->embed = is_embed; if (kind == _cpp_FFK_FAKE) file->dont_read = true; @@ -551,10 +566,17 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, if (find_file_in_dir (pfile, file, &invalid_pch, loc)) break; - file->dir = file->dir->next; + if (is_embed + && file->dir == start_dir + && start_dir != pfile->embed_include + && start_dir != &pfile->no_search_path) + file->dir = pfile->embed_include; + else + file->dir = file->dir->next; if (file->dir == NULL) { - if (search_path_exhausted (pfile, fname, file)) + if (!is_embed + && search_path_exhausted (pfile, fname, file)) { /* Although this file must not go in the cache, because the file found might depend on things (like @@ -601,7 +623,7 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, return NULL; } - if (kind != _cpp_FFK_HAS_INCLUDE) + if (kind != _cpp_FFK_HAS_INCLUDE && kind != _cpp_FFK_HAS_EMBED) open_file_failed (pfile, file, angle_brackets, loc); else file->deferred_error = true; @@ -615,11 +637,14 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, saw_bracket_include = true; else if (file->dir == pfile->quote_include) saw_quote_include = true; + else if (file->dir == pfile->embed_include) + saw_embed_include = true; else continue; entry - = search_cache ((struct cpp_file_hash_entry *) *hash_slot, file->dir); + = search_cache ((struct cpp_file_hash_entry *) *hash_slot, + file->dir, is_embed); if (entry) { found_in_cache = file->dir; @@ -673,6 +698,17 @@ _cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, entry->u.file = file; *hash_slot = (void *) entry; } + if (saw_embed_include + && pfile->embed_include != start_dir + && found_in_cache != pfile->embed_include) + { + entry = new_file_hash_entry (pfile); + entry->next = (struct cpp_file_hash_entry *) *hash_slot; + entry->start_dir = pfile->embed_include; + entry->location = loc; + entry->u.file = file; + *hash_slot = (void *) entry; + } return file; } @@ -693,7 +729,7 @@ static bool read_file_guts (cpp_reader *pfile, _cpp_file *file, location_t loc, const char *input_charset) { - ssize_t size, total, count; + ssize_t size, pad, total, count; uchar *buf; bool regular; @@ -732,11 +768,10 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file, location_t loc, the majority of C source files. */ size = 8 * 1024; - /* The + 16 here is space for the final '\n' and 15 bytes of padding, - used to quiet warnings from valgrind or Address Sanitizer, when the - optimized lexer accesses aligned 16-byte memory chunks, including - the bytes after the malloced, area, and stops lexing on '\n'. */ - buf = XNEWVEC (uchar, size + 16); + pad = CPP_BUFFER_PADDING; + /* The '+ PAD' here is space for the final '\n' and PAD-1 bytes of padding, + allowing search_line_fast to use (possibly misaligned) vector loads. */ + buf = XNEWVEC (uchar, size + pad); total = 0; while ((count = read (file->fd, buf + total, size - total)) > 0) { @@ -747,7 +782,7 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file, location_t loc, if (regular) break; size *= 2; - buf = XRESIZEVEC (uchar, buf, size + 16); + buf = XRESIZEVEC (uchar, buf, size + pad); } } @@ -761,11 +796,11 @@ read_file_guts (cpp_reader *pfile, _cpp_file *file, location_t loc, if (pfile && regular && total != size && STAT_SIZE_RELIABLE (file->st)) cpp_error_at (pfile, CPP_DL_WARNING, loc, - "%s is shorter than expected", file->path); + "%s is shorter than expected", file->path); file->buffer = _cpp_convert_input (pfile, input_charset, - buf, size + 16, total, + buf, size + pad, total, &file->buffer_start, &file->st.st_size); file->buffer_valid = file->buffer; @@ -872,6 +907,9 @@ has_unique_contents (cpp_reader *pfile, _cpp_file *file, bool import, if (f == file) continue; /* It'sa me! */ + if (f->embed) + continue; + if ((import || f->once_only) && f->err_no == 0 && f->st.st_mtime == file->st.st_mtime @@ -1063,12 +1101,12 @@ search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets, && file->dir != &pfile->no_search_path) dir = file->dir->next; else if (angle_brackets) - dir = pfile->bracket_include; + dir = type == IT_EMBED ? pfile->embed_include : pfile->bracket_include; else if (type == IT_CMDLINE) /* -include and -imacros use the #include "" chain with the preprocessor's cwd prepended. */ return make_cpp_dir (pfile, "./", false); - else if (pfile->quote_ignores_source_dir) + else if (pfile->quote_ignores_source_dir && type != IT_EMBED) dir = pfile->quote_include; else return make_cpp_dir (pfile, dir_name_of_file (file), @@ -1182,6 +1220,554 @@ cpp_probe_header_unit (cpp_reader *pfile, const char *name, bool angle, return nullptr; } +/* Helper function for _cpp_stack_embed. Finish #embed/__has_embed processing + after a file is found and data loaded into buffer. */ + +static int +finish_embed (cpp_reader *pfile, _cpp_file *file, + struct cpp_embed_params *params) +{ + const uchar *buffer = file->buffer; + size_t limit = file->limit; + if (params->offset - file->offset > limit) + limit = 0; + else + { + buffer += params->offset - file->offset; + limit -= params->offset - file->offset; + } + if (params->limit < limit) + limit = params->limit; + + /* For sizes larger than say 64 bytes, this is just a temporary + solution, we should emit a single new token which the FEs will + handle as an optimization. */ + size_t max = INTTYPE_MAXIMUM (size_t) / sizeof (cpp_token); + if (limit > max / 2 + || (limit + ? (params->prefix.count > max + || params->suffix.count > max + || (limit * 2 - 1 + params->prefix.count + + params->suffix.count > max)) + : params->if_empty.count > max)) + { + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "%s is too large", file->path); + return 0; + } + + size_t len = 0; + for (size_t i = 0; i < limit; ++i) + { + if (buffer[i] < 10) + len += 2; + else if (buffer[i] < 100) + len += 3; +#if UCHAR_MAX == 255 + else + len += 4; +#else + else if (buffer[i] < 1000) + len += 4; + else + { + char buf[64]; + len += sprintf (buf, "%d", buffer[i]) + 1; + } +#endif + if (len > INTTYPE_MAXIMUM (ssize_t)) + { + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "%s is too large", file->path); + return 0; + } + } + uchar *s = len ? _cpp_unaligned_alloc (pfile, len) : NULL; + _cpp_buff *tok_buff = NULL; + cpp_token *tok = &pfile->directive_result, *toks = tok; + size_t count = 0; + if (limit) + count = (params->prefix.count + limit * 2 - 1 + + params->suffix.count) - 1; + else if (params->if_empty.count) + count = params->if_empty.count - 1; + if (count) + { + tok_buff = _cpp_get_buff (pfile, count * sizeof (cpp_token)); + toks = (cpp_token *) tok_buff->base; + } + cpp_embed_params_tokens *prefix + = limit ? ¶ms->prefix : ¶ms->if_empty; + if (prefix->count) + { + *tok = *prefix->base_run.base; + tok = toks; + tokenrun *cur_run = &prefix->base_run; + while (cur_run) + { + size_t cnt = (cur_run->next ? cur_run->limit + : prefix->cur_token) - cur_run->base; + cpp_token *t = cur_run->base; + if (cur_run == &prefix->base_run) + { + t++; + cnt--; + } + memcpy (tok, t, cnt * sizeof (cpp_token)); + tok += cnt; + cur_run = cur_run->next; + } + } + for (size_t i = 0; i < limit; ++i) + { + tok->src_loc = params->loc; + tok->type = CPP_NUMBER; + tok->flags = NO_EXPAND; + if (i == 0) + tok->flags |= PREV_WHITE; + tok->val.str.text = s; + tok->val.str.len = sprintf ((char *) s, "%d", buffer[i]); + s += tok->val.str.len + 1; + if (tok == &pfile->directive_result) + tok = toks; + else + tok++; + if (i < limit - 1) + { + tok->src_loc = params->loc; + tok->type = CPP_COMMA; + tok->flags = NO_EXPAND; + tok++; + } + } + if (limit && params->suffix.count) + { + tokenrun *cur_run = ¶ms->suffix.base_run; + cpp_token *orig_tok = tok; + while (cur_run) + { + size_t cnt = (cur_run->next ? cur_run->limit + : params->suffix.cur_token) - cur_run->base; + cpp_token *t = cur_run->base; + memcpy (tok, t, cnt * sizeof (cpp_token)); + tok += cnt; + cur_run = cur_run->next; + } + orig_tok->flags |= PREV_WHITE; + } + pfile->directive_result.flags |= PREV_WHITE; + if (count) + { + _cpp_push_token_context (pfile, NULL, toks, count); + pfile->context->buff = tok_buff; + } + return limit ? 1 : 2; +} + +/* Helper function for initialization of base64_dec table. + Can't rely on ASCII compatibility, so check each letter + separately. */ + +constexpr signed char +base64_dec_fn (unsigned char c) +{ + return (c == 'A' ? 0 : c == 'B' ? 1 : c == 'C' ? 2 : c == 'D' ? 3 + : c == 'E' ? 4 : c == 'F' ? 5 : c == 'G' ? 6 : c == 'H' ? 7 + : c == 'I' ? 8 : c == 'J' ? 9 : c == 'K' ? 10 : c == 'L' ? 11 + : c == 'M' ? 12 : c == 'N' ? 13 : c == 'O' ? 14 : c == 'P' ? 15 + : c == 'Q' ? 16 : c == 'R' ? 17 : c == 'S' ? 18 : c == 'T' ? 19 + : c == 'U' ? 20 : c == 'V' ? 21 : c == 'W' ? 22 : c == 'X' ? 23 + : c == 'Y' ? 24 : c == 'Z' ? 25 + : c == 'a' ? 26 : c == 'b' ? 27 : c == 'c' ? 28 : c == 'd' ? 29 + : c == 'e' ? 30 : c == 'f' ? 31 : c == 'g' ? 32 : c == 'h' ? 33 + : c == 'i' ? 34 : c == 'j' ? 35 : c == 'k' ? 36 : c == 'l' ? 37 + : c == 'm' ? 38 : c == 'n' ? 39 : c == 'o' ? 40 : c == 'p' ? 41 + : c == 'q' ? 42 : c == 'r' ? 43 : c == 's' ? 44 : c == 't' ? 45 + : c == 'u' ? 46 : c == 'v' ? 47 : c == 'w' ? 48 : c == 'x' ? 49 + : c == 'y' ? 50 : c == 'z' ? 51 + : c == '0' ? 52 : c == '1' ? 53 : c == '2' ? 54 : c == '3' ? 55 + : c == '4' ? 56 : c == '5' ? 57 : c == '6' ? 58 : c == '7' ? 59 + : c == '8' ? 60 : c == '9' ? 61 : c == '+' ? 62 : c == '/' ? 63 + : -1); +} + +/* base64 decoding table. */ + +static constexpr signed char base64_dec[] = { +#define B64D0(x) base64_dec_fn (x) +#define B64D1(x) B64D0 (x), B64D0 (x + 1), B64D0 (x + 2), B64D0 (x + 3) +#define B64D2(x) B64D1 (x), B64D1 (x + 4), B64D1 (x + 8), B64D1 (x + 12) +#define B64D3(x) B64D2 (x), B64D2 (x + 16), B64D2 (x + 32), B64D2 (x + 48) + B64D3 (0), B64D3 (64), B64D3 (128), B64D3 (192) +}; + +/* Helper function for _cpp_stack_embed. Handle #embed/__has_embed with + gnu::base64 parameter. */ + +static int +finish_base64_embed (cpp_reader *pfile, const char *fname, bool angle, + struct cpp_embed_params *params) +{ + size_t len, end, i, j, base64_len = 0, cnt; + uchar *buf = NULL, *q, pbuf[4], qbuf[3]; + const uchar *base64_str; + if (angle || strcmp (fname, ".")) + { + if (!params->has_embed) + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "'gnu::base64' parameter can be only used with \".\""); + return 0; + } + tokenrun *cur_run = ¶ms->base64.base_run; + cpp_token *tend, *tok; + while (cur_run) + { + tend = cur_run->next ? cur_run->limit : params->base64.cur_token; + for (tok = cur_run->base; tok < tend; ++tok) + { + if (tok->val.str.len < 2 + || tok->val.str.text[0] != '"' + || tok->val.str.text[tok->val.str.len - 1] != '"') + { + fail: + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "'gnu::base64' argument not valid base64 " + "encoded string"); + free (buf); + return 0; + } + if (tok->val.str.len - 2 > (~(size_t) 0) - base64_len) + goto fail; + base64_len += tok->val.str.len - 2; + } + cur_run = cur_run->next; + } + if ((base64_len & 3) != 0) + goto fail; + len = base64_len / 4 * 3; + end = len; + + if (params->has_embed) + q = qbuf; + else + { + buf = XNEWVEC (uchar, len ? len : 1); + q = buf; + } + cur_run = ¶ms->base64.base_run; + tend = cur_run->next ? cur_run->limit : params->base64.cur_token; + tok = cur_run->base; + base64_str = tok->val.str.text + 1; + cnt = tok->val.str.len - 2; + ++tok; + for (i = 0; i < end; i += 3) + { + for (j = 0; j < 4; ++j) + { + while (cnt == 0) + { + if (tok == tend) + { + cur_run = cur_run->next; + tend = (cur_run->next ? cur_run->limit + : params->base64.cur_token); + tok = cur_run->base; + } + base64_str = tok->val.str.text + 1; + cnt = tok->val.str.len - 2; + ++tok; + } + pbuf[j] = *base64_str; + base64_str++; + --cnt; + } + if (pbuf[3] == '=' && i + 3 >= end) + { + end = len - 3; + --len; + if (pbuf[2] == '=') + --len; + break; + } + int a = base64_dec[pbuf[0]]; + int b = base64_dec[pbuf[1]]; + int c = base64_dec[pbuf[2]]; + int d = base64_dec[pbuf[3]]; + if (a == -1 || b == -1 || c == -1 || d == -1) + goto fail; + q[0] = (a << 2) | (b >> 4); + q[1] = (b << 4) | (c >> 2); + q[2] = (c << 6) | d; + if (!params->has_embed) + q += 3; + } + if (len != end) + { + int a = base64_dec[pbuf[0]]; + int b = base64_dec[pbuf[1]]; + if (a == -1 || b == -1) + goto fail; + q[0] = (a << 2) | (b >> 4); + if (len - end == 2) + { + int c = base64_dec[pbuf[2]]; + if (c == -1) + goto fail; + q[1] = (b << 4) | (c >> 2); + if ((c & 3) != 0) + goto fail; + } + else if ((b & 15) != 0) + goto fail; + } + if (params->has_embed) + return len ? 1 : 2; + _cpp_file *file = make_cpp_file (NULL, ""); + file->embed = 1; + file->next_file = pfile->all_files; + pfile->all_files = file; + params->limit = -1; + params->offset = 0; + file->limit = len; + file->buffer = buf; + file->path = xstrdup ("<base64>"); + return finish_embed (pfile, file, params); +} + +/* Try to load FNAME with #embed/__has_embed parameters PARAMS. + If !PARAMS->has_embed, return new token in pfile->directive_result + (first token) and rest in a pushed non-macro context. + Returns 0 for not found/errors, 1 for non-empty resource and 2 + for empty resource. */ + +int +_cpp_stack_embed (cpp_reader *pfile, const char *fname, bool angle, + struct cpp_embed_params *params) +{ + if (params->base64.count) + return finish_base64_embed (pfile, fname, angle, params); + cpp_dir *dir = search_path_head (pfile, fname, angle, IT_EMBED, + params->has_embed); + if (!dir) + return 0; + _cpp_file *file = _cpp_find_file (pfile, fname, dir, angle, + params->has_embed + ? _cpp_FFK_HAS_EMBED : _cpp_FFK_EMBED, + params->loc); + if (!file) + return 0; + if (file->dont_read || file->err_no) + return 0; + _cpp_file *orig_file = file; + if (file->buffer_valid + && (!S_ISREG (file->st.st_mode) + || file->offset + (cpp_num_part) 0 > params->offset + || (file->limit < file->st.st_size - file->offset + (size_t) 0 + && (params->offset - file->offset > (cpp_num_part) file->limit + || file->limit - (params->offset + - file->offset) < params->limit)))) + { + bool found = false; + if (S_ISREG (file->st.st_mode)) + { + while (file->next_file + && file->next_file->embed + && file->next_file->buffer_valid + && file->next_file->dir == file->dir + && strcmp (file->name, file->next_file->name) == 0 + && strcmp (file->path, file->next_file->path) == 0) + { + file = file->next_file; + if (file->offset + (cpp_num_part) 0 <= params->offset + && (file->limit >= (file->st.st_size - file->offset + + (size_t) 0) + || (params->offset + - file->offset <= (cpp_num_part) file->limit + && file->limit - (params->offset + - file->offset) >= params->limit))) + { + found = true; + break; + } + } + } + if (!found) + { + _cpp_file *file2 = make_cpp_file (file->dir, file->name); + file2->path = xstrdup (file->path); + file2->next_file = file->next_file; + file2->embed = true; + file->next_file = file2; + file = file2; + } + } + if (!file->buffer_valid) + { + if (file->fd == -1 && !open_file (file)) + { + if (params->has_embed) + file->deferred_error = true; + else + open_file_failed (pfile, file, 0, params->loc); + return 0; + } + if (S_ISBLK (file->st.st_mode)) + { + if (params->has_embed) + { + close (file->fd); + file->fd = -1; + return 0; + } + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "%s is a block device", file->path); + fail: + close (file->fd); + file->fd = -1; + file->dont_read = true; + return 0; + } + + if (CPP_OPTION (pfile, deps.style) + && !params->has_embed + && file == orig_file + && file->path[0]) + deps_add_dep (pfile->deps, file->path); + + bool regular = S_ISREG (file->st.st_mode) != 0; + ssize_t size, total, count; + uchar *buf; + if (regular) + { + cpp_num_part limit; + if (file->st.st_size + (cpp_num_part) 0 < params->offset) + limit = 0; + else if (file->st.st_size - params->offset < params->limit) + limit = file->st.st_size - params->offset; + else + limit = params->limit; + if (params->has_embed) + return limit != 0 ? 1 : 2; + if (limit > INTTYPE_MAXIMUM (ssize_t)) + { + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "%s is too large", file->path); + goto fail; + } + if (lseek (file->fd, params->offset, SEEK_CUR) + != (off_t) params->offset) + { + cpp_errno_filename (pfile, CPP_DL_ERROR, file->path, + params->loc); + goto fail; + } + file->offset = params->offset; + file->limit = limit; + size = limit; + } + else if (params->has_embed) + return 2; + else if (params->limit > 8 * 1024) + size = 8 * 1024; + else + size = params->limit; + buf = XNEWVEC (uchar, size ? size : 1); + total = 0; + + if (!regular && params->offset) + { + uchar *buf2 = buf; + ssize_t size2 = size; + cpp_num_part total2 = params->offset; + + if (params->offset > 8 * 1024 && size < 8 * 1024) + { + size2 = 32 * 1024; + buf2 = XNEWVEC (uchar, size2); + } + do + { + if ((cpp_num_part) size2 > total2) + size2 = total2; + count = read (file->fd, buf2, size2); + if (count < 0) + { + cpp_errno_filename (pfile, CPP_DL_ERROR, file->path, + params->loc); + if (buf2 != buf) + free (buf2); + free (buf); + goto fail; + } + total2 -= count; + } + while (total2); + if (buf2 != buf) + free (buf2); + } + + while ((count = read (file->fd, buf + total, size - total)) > 0) + { + total += count; + if (total == size) + { + if (regular || size + (cpp_num_part) 0 == params->limit) + break; + size = (size_t) size * 2; + if (size < 0) + { + if (params->limit <= INTTYPE_MAXIMUM (ssize_t)) + size = params->limit; + else + { + cpp_error_at (pfile, CPP_DL_ERROR, params->loc, + "%s is too large", file->path); + free (buf); + goto fail; + } + } + else if (size + (cpp_num_part) 0 > params->limit) + size = params->limit; + buf = XRESIZEVEC (uchar, buf, size); + } + } + + if (count < 0) + { + cpp_errno_filename (pfile, CPP_DL_ERROR, file->path, params->loc); + free (buf); + goto fail; + } + + if (regular && total != size && STAT_SIZE_RELIABLE (file->st)) + { + cpp_error_at (pfile, CPP_DL_WARNING, params->loc, + "%s is shorter than expected", file->path); + file->limit = total; + } + else if (!regular) + { + file->offset = params->offset; + file->limit = total; + } + + file->buffer_start = buf; + file->buffer = buf; + file->buffer_valid = 1; + close (file->fd); + file->fd = -1; + } + else if (params->has_embed) + { + if (params->offset - file->offset > file->limit) + return 2; + size_t limit = file->limit - (params->offset - file->offset); + return limit && params->limit ? 1 : 2; + } + + return finish_embed (pfile, file, params); +} + /* Retrofit the just-entered main file asif it was an include. This will permit correct include_next use, and mark it as a system header if that's where it resides. We use filesystem-appropriate @@ -1257,9 +1843,11 @@ open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets, /* Search in the chain beginning at HEAD for a file whose search path started at START_DIR != NULL. */ static struct cpp_file_hash_entry * -search_cache (struct cpp_file_hash_entry *head, const cpp_dir *start_dir) +search_cache (struct cpp_file_hash_entry *head, const cpp_dir *start_dir, + bool is_embed) { - while (head && head->start_dir != start_dir) + while (head && (head->start_dir != start_dir + || head->u.file->embed != is_embed)) head = head->next; return head; @@ -1693,21 +2281,24 @@ _cpp_get_file_name (_cpp_file *file) struct stat * _cpp_get_file_stat (_cpp_file *file) { - return &file->st; + return &file->st; } /* Set the include chain for "" to QUOTE, for <> to BRACKET. If QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the directory of the including file. - If BRACKET does not lie in the QUOTE chain, it is set to QUOTE. */ + If BRACKET does not lie in the QUOTE chain, it is set to QUOTE. + + EMBED is include chain for #embed <>. */ void cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket, - int quote_ignores_source_dir) + cpp_dir *embed, int quote_ignores_source_dir) { pfile->quote_include = quote; pfile->bracket_include = quote; pfile->quote_ignores_source_dir = quote_ignores_source_dir; + pfile->embed_include = embed; for (; quote; quote = quote->next) { @@ -1716,6 +2307,11 @@ cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket, if (quote == bracket) pfile->bracket_include = bracket; } + for (; embed; embed = embed->next) + { + embed->name_map = NULL; + embed->len = strlen (embed->name); + } } /* Append the file name to the directory to create the path, but don't diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index d76817c..76e2437 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -545,6 +545,9 @@ struct cpp_options /* Nonzero for 'true' and 'false' in #if expressions. */ unsigned char true_false; + /* Nonzero for the '#embed' directive. */ + unsigned char embed; + /* Holds the name of the target (execution) character set. */ const char *narrow_charset; @@ -699,6 +702,10 @@ enum cpp_warning_reason { CPP_W_C11_C23_COMPAT, CPP_W_CXX11_COMPAT, CPP_W_CXX20_COMPAT, + CPP_W_CXX14_EXTENSIONS, + CPP_W_CXX17_EXTENSIONS, + CPP_W_CXX20_EXTENSIONS, + CPP_W_CXX23_EXTENSIONS, CPP_W_EXPANSION_TO_DEFINED, CPP_W_BIDIRECTIONAL, CPP_W_INVALID_UTF8, @@ -974,6 +981,7 @@ enum cpp_builtin_type BT_HAS_BUILTIN, /* `__has_builtin(x)' */ BT_HAS_INCLUDE, /* `__has_include(x)' */ BT_HAS_INCLUDE_NEXT, /* `__has_include_next(x)' */ + BT_HAS_EMBED, /* `__has_embed(x)' */ BT_HAS_FEATURE, /* `__has_feature(x)' */ BT_HAS_EXTENSION /* `__has_extension(x)' */ }; @@ -1092,7 +1100,8 @@ extern void cpp_set_line_map (cpp_reader *, class line_maps *); extern void cpp_set_lang (cpp_reader *, enum c_lang); /* Set the include paths. */ -extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int); +extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, + cpp_dir *, int); /* Call these to get pointers to the options, callback, and deps structures for a given reader. These pointers are good until you diff --git a/libcpp/init.cc b/libcpp/init.cc index 9ae06a9..b22481c 100644 --- a/libcpp/init.cc +++ b/libcpp/init.cc @@ -77,61 +77,68 @@ END requires. */ struct lang_flags { - char c99; - char cplusplus; - char extended_numbers; - char extended_identifiers; - char c11_identifiers; - char xid_identifiers; - char std; - char digraphs; - char uliterals; - char rliterals; - char user_literals; - char binary_constants; - char digit_separators; - char trigraphs; - char utf8_char_literals; - char va_opt; - char scope; - char dfp_constants; - char size_t_literals; - char elifdef; - char warning_directive; - char delimited_escape_seqs; - char true_false; + unsigned int c99 : 1; + unsigned int cplusplus : 1; + unsigned int extended_numbers : 1; + unsigned int extended_identifiers : 1; + unsigned int c11_identifiers : 1; + unsigned int xid_identifiers : 1; + unsigned int std : 1; + unsigned int digraphs : 1; + unsigned int uliterals : 1; + unsigned int rliterals : 1; + unsigned int user_literals : 1; + unsigned int binary_constants : 1; + unsigned int digit_separators : 1; + unsigned int trigraphs : 1; + unsigned int utf8_char_literals : 1; + unsigned int va_opt : 1; + unsigned int scope : 1; + unsigned int dfp_constants : 1; + unsigned int size_t_literals : 1; + unsigned int elifdef : 1; + unsigned int warning_directive : 1; + unsigned int delimited_escape_seqs : 1; + unsigned int true_false : 1; + unsigned int embed : 1; }; -static const struct lang_flags lang_defaults[] = -{ /* c99 c++ xnum xid c11 xidid std digr ulit rlit udlit bincst digsep trig u8chlit vaopt scope dfp szlit elifdef warndir delim trufal */ - /* GNUC89 */ { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, - /* GNUC99 */ { 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, - /* GNUC11 */ { 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, - /* GNUC17 */ { 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, - /* GNUC23 */ { 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 }, - /* GNUC2Y */ { 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 }, - /* STDC89 */ { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* STDC94 */ { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* STDC99 */ { 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* STDC11 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* STDC17 */ { 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* STDC23 */ { 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 }, - /* STDC2Y */ { 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 }, - /* GNUCXX */ { 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* CXX98 */ { 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUCXX11 */ { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* CXX11 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUCXX14 */ { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* CXX14 */ { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUCXX17 */ { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* CXX17 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUCXX20 */ { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* CXX20 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, - /* GNUCXX23 */ { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, - /* CXX23 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, - /* GNUCXX26 */ { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, - /* CXX26 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, - /* ASM */ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +static const struct lang_flags lang_defaults[] = { + /* u e w + b d 8 l a t + x u i i c v s s i r d r e + x i d u r d n g t h a c z f n e u m + c c n x c d s i l l l c s r l o o d l d d l f b + 9 + u i 1 i t g i i i s e i i p p f i e i i a e + 9 + m d 1 d d r t t t t p g t t e p t f r m l d */ + /* GNUC89 */ { 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0 }, + /* GNUC99 */ { 1,0,1,1,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0 }, + /* GNUC11 */ { 1,0,1,1,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0 }, + /* GNUC17 */ { 1,0,1,1,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0 }, + /* GNUC23 */ { 1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1 }, + /* GNUC2Y */ { 1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1 }, + /* STDC89 */ { 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 }, + /* STDC94 */ { 0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 }, + /* STDC99 */ { 1,0,1,1,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 }, + /* STDC11 */ { 1,0,1,1,1,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 }, + /* STDC17 */ { 1,0,1,1,1,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 }, + /* STDC23 */ { 1,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,1,1 }, + /* STDC2Y */ { 1,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,1,1 }, + /* GNUCXX */ { 0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0 }, + /* CXX98 */ { 0,1,0,1,0,1,1,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0 }, + /* GNUCXX11 */ { 1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,0 }, + /* CXX11 */ { 1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,0,0,0,1,0 }, + /* GNUCXX14 */ { 1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,1,0 }, + /* CXX14 */ { 1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,0,1,0 }, + /* GNUCXX17 */ { 1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,1,0 }, + /* CXX17 */ { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,0 }, + /* GNUCXX20 */ { 1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,1,0 }, + /* CXX20 */ { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,1,0 }, + /* GNUCXX23 */ { 1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0 }, + /* CXX23 */ { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0 }, + /* GNUCXX26 */ { 1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0 }, + /* CXX26 */ { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0 }, + /* ASM */ { 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }; /* Sets internal flags correctly for a given language. */ @@ -165,6 +172,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang) CPP_OPTION (pfile, warning_directive) = l->warning_directive; CPP_OPTION (pfile, delimited_escape_seqs) = l->delimited_escape_seqs; CPP_OPTION (pfile, true_false) = l->true_false; + CPP_OPTION (pfile, embed) = l->embed; } /* Initialize library global state. */ @@ -437,6 +445,7 @@ static const struct builtin_macro builtin_array[] = B("__has_builtin", BT_HAS_BUILTIN, true), B("__has_include", BT_HAS_INCLUDE, true), B("__has_include_next",BT_HAS_INCLUDE_NEXT, true), + B("__has_embed", BT_HAS_EMBED, true), B("__has_feature", BT_HAS_FEATURE, true), B("__has_extension", BT_HAS_EXTENSION, true), /* Keep builtins not used for -traditional-cpp at the end, and @@ -623,6 +632,10 @@ cpp_init_builtins (cpp_reader *pfile, int hosted) else _cpp_define_builtin (pfile, "__STDC_HOSTED__ 0"); + _cpp_define_builtin (pfile, "__STDC_EMBED_NOT_FOUND__ 0"); + _cpp_define_builtin (pfile, "__STDC_EMBED_FOUND__ 1"); + _cpp_define_builtin (pfile, "__STDC_EMBED_EMPTY__ 2"); + if (CPP_OPTION (pfile, objc)) _cpp_define_builtin (pfile, "__OBJC__ 1"); } diff --git a/libcpp/internal.h b/libcpp/internal.h index a20215c..fa64a69 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -122,6 +122,7 @@ enum include_type IT_INCLUDE, /* #include */ IT_INCLUDE_NEXT, /* #include_next */ IT_IMPORT, /* #import */ + IT_EMBED, /* #embed */ /* Non-directive including mechanisms. */ IT_CMDLINE, /* -include */ @@ -322,6 +323,13 @@ struct _cpp_line_note unsigned int type; }; +/* Tail padding required by search_line_fast alternatives. */ +#ifdef HAVE_SSSE3 +#define CPP_BUFFER_PADDING 64 +#else +#define CPP_BUFFER_PADDING 16 +#endif + /* Represents the contents of a file cpplib has read in. */ struct cpp_buffer { @@ -463,6 +471,7 @@ struct cpp_reader struct cpp_dir *quote_include; /* "" */ struct cpp_dir *bracket_include; /* <> */ struct cpp_dir no_search_path; /* No path. */ + struct cpp_dir *embed_include; /* #embed <> */ /* Chain of all hashed _cpp_file instances. */ struct _cpp_file *all_files; @@ -614,6 +623,24 @@ struct cpp_reader } }; +/* Lists of tokens for #embed/__has_embed prefix/suffix/if_empty + parameters. */ +struct cpp_embed_params_tokens +{ + cpp_token *cur_token; + tokenrun base_run, *cur_run; + size_t count; +}; + +/* #embed and __has_embed parameters. */ +struct cpp_embed_params +{ + location_t loc; + bool has_embed; + cpp_num_part limit, offset; + cpp_embed_params_tokens prefix, suffix, if_empty, base64; +}; + /* Character classes. Based on the more primitive macros in safe-ctype.h. If the definition of `numchar' looks odd to you, please look up the definition of a pp-number in the C standard [section 6.4.8 of C99]. @@ -702,6 +729,7 @@ extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *, extern const unsigned char *_cpp_builtin_macro_text (cpp_reader *, cpp_hashnode *, location_t = 0); +extern const cpp_token *_cpp_get_token_no_padding (cpp_reader *); extern int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *); extern void _cpp_push_token_context (cpp_reader *, cpp_hashnode *, const cpp_token *, unsigned int); @@ -714,13 +742,16 @@ extern void _cpp_destroy_hashtable (cpp_reader *); /* In files.cc */ enum _cpp_find_file_kind - { _cpp_FFK_NORMAL, _cpp_FFK_FAKE, _cpp_FFK_PRE_INCLUDE, _cpp_FFK_HAS_INCLUDE }; + { _cpp_FFK_NORMAL, _cpp_FFK_FAKE, _cpp_FFK_PRE_INCLUDE, _cpp_FFK_HAS_INCLUDE, + _cpp_FFK_EMBED, _cpp_FFK_HAS_EMBED }; extern _cpp_file *_cpp_find_file (cpp_reader *, const char *, cpp_dir *, int angle, _cpp_find_file_kind, location_t); extern bool _cpp_find_failed (_cpp_file *); extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *); extern const char *_cpp_find_header_unit (cpp_reader *, const char *file, bool angle_p, location_t); +extern int _cpp_stack_embed (cpp_reader *, const char *, bool, + cpp_embed_params *); extern void _cpp_fake_include (cpp_reader *, const char *); extern bool _cpp_stack_file (cpp_reader *, _cpp_file*, include_type, location_t); extern bool _cpp_stack_include (cpp_reader *, const char *, int, @@ -739,7 +770,8 @@ extern bool _cpp_has_header (cpp_reader *, const char *, int, enum include_type); /* In expr.cc */ -extern bool _cpp_parse_expr (cpp_reader *, bool); +extern cpp_num_part _cpp_parse_expr (cpp_reader *, const char *, + const cpp_token *); extern struct op *_cpp_expand_op_stack (cpp_reader *); /* In lex.cc */ @@ -780,6 +812,8 @@ extern void _cpp_restore_pragma_names (cpp_reader *, char **); extern int _cpp_do__Pragma (cpp_reader *, location_t); extern void _cpp_init_directives (cpp_reader *); extern void _cpp_init_internal_pragmas (cpp_reader *); +extern void _cpp_free_embed_params_tokens (cpp_embed_params_tokens *); +extern bool _cpp_parse_embed_params (cpp_reader *, struct cpp_embed_params *); extern void _cpp_do_file_change (cpp_reader *, enum lc_reason, const char *, linenum_type, unsigned int); extern void _cpp_pop_buffer (cpp_reader *); diff --git a/libcpp/lex.cc b/libcpp/lex.cc index 16f2c23..4025e5c 100644 --- a/libcpp/lex.cc +++ b/libcpp/lex.cc @@ -225,10 +225,7 @@ acc_char_index (word_type cmp ATTRIBUTE_UNUSED, and branches without increasing the number of arithmetic operations. It's almost certainly going to be a win with 64-bit word size. */ -static const uchar * search_line_acc_char (const uchar *, const uchar *) - ATTRIBUTE_UNUSED; - -static const uchar * +static inline const uchar * search_line_acc_char (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) { const word_type repl_nl = acc_char_replicate ('\n'); @@ -290,75 +287,10 @@ static const char repl_chars[4][16] __attribute__((aligned(16))) = { '?', '?', '?', '?', '?', '?', '?', '?' }, }; -/* A version of the fast scanner using MMX vectorized byte compare insns. - - This uses the PMOVMSKB instruction which was introduced with "MMX2", - which was packaged into SSE1; it is also present in the AMD MMX - extension. Mark the function as using "sse" so that we emit a real - "emms" instruction, rather than the 3dNOW "femms" instruction. */ - -static const uchar * -#ifndef __SSE__ -__attribute__((__target__("sse"))) -#endif -search_line_mmx (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) -{ - typedef char v8qi __attribute__ ((__vector_size__ (8))); - typedef int __m64 __attribute__ ((__vector_size__ (8), __may_alias__)); - - const v8qi repl_nl = *(const v8qi *)repl_chars[0]; - const v8qi repl_cr = *(const v8qi *)repl_chars[1]; - const v8qi repl_bs = *(const v8qi *)repl_chars[2]; - const v8qi repl_qm = *(const v8qi *)repl_chars[3]; - - unsigned int misalign, found, mask; - const v8qi *p; - v8qi data, t, c; - - /* Align the source pointer. While MMX doesn't generate unaligned data - faults, this allows us to safely scan to the end of the buffer without - reading beyond the end of the last page. */ - misalign = (uintptr_t)s & 7; - p = (const v8qi *)((uintptr_t)s & -8); - data = *p; - - /* Create a mask for the bytes that are valid within the first - 16-byte block. The Idea here is that the AND with the mask - within the loop is "free", since we need some AND or TEST - insn in order to set the flags for the branch anyway. */ - mask = -1u << misalign; - - /* Main loop processing 8 bytes at a time. */ - goto start; - do - { - data = *++p; - mask = -1; - - start: - t = __builtin_ia32_pcmpeqb(data, repl_nl); - c = __builtin_ia32_pcmpeqb(data, repl_cr); - t = (v8qi) __builtin_ia32_por ((__m64)t, (__m64)c); - c = __builtin_ia32_pcmpeqb(data, repl_bs); - t = (v8qi) __builtin_ia32_por ((__m64)t, (__m64)c); - c = __builtin_ia32_pcmpeqb(data, repl_qm); - t = (v8qi) __builtin_ia32_por ((__m64)t, (__m64)c); - found = __builtin_ia32_pmovmskb (t); - found &= mask; - } - while (!found); - - __builtin_ia32_emms (); - - /* FOUND contains 1 in bits for which we matched a relevant - character. Conversion to the byte index is trivial. */ - found = __builtin_ctz(found); - return (const uchar *)p + found; -} /* A version of the fast scanner using SSE2 vectorized byte compare insns. */ -static const uchar * +static inline const uchar * #ifndef __SSE2__ __attribute__((__target__("sse2"))) #endif @@ -409,130 +341,84 @@ search_line_sse2 (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) return (const uchar *)p + found; } -#ifdef HAVE_SSE4 -/* A version of the fast scanner using SSE 4.2 vectorized string insns. */ +#ifdef HAVE_SSSE3 +/* A version of the fast scanner using SSSE3 shuffle (PSHUFB) insns. */ -static const uchar * -#ifndef __SSE4_2__ -__attribute__((__target__("sse4.2"))) +static inline const uchar * +#ifndef __SSSE3__ +__attribute__((__target__("ssse3"))) #endif -search_line_sse42 (const uchar *s, const uchar *end) +search_line_ssse3 (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) { typedef char v16qi __attribute__ ((__vector_size__ (16))); - static const v16qi search = { '\n', '\r', '?', '\\' }; - - uintptr_t si = (uintptr_t)s; - uintptr_t index; - - /* Check for unaligned input. */ - if (si & 15) - { - v16qi sv; - - if (__builtin_expect (end - s < 16, 0) - && __builtin_expect ((si & 0xfff) > 0xff0, 0)) - { - /* There are less than 16 bytes left in the buffer, and less - than 16 bytes left on the page. Reading 16 bytes at this - point might generate a spurious page fault. Defer to the - SSE2 implementation, which already handles alignment. */ - return search_line_sse2 (s, end); - } - - /* ??? The builtin doesn't understand that the PCMPESTRI read from - memory need not be aligned. */ - sv = __builtin_ia32_loaddqu ((const char *) s); - index = __builtin_ia32_pcmpestri128 (search, 4, sv, 16, 0); - - if (__builtin_expect (index < 16, 0)) - goto found; - - /* Advance the pointer to an aligned address. We will re-scan a - few bytes, but we no longer need care for reading past the - end of a page, since we're guaranteed a match. */ - s = (const uchar *)((si + 15) & -16); - } - - /* Main loop, processing 16 bytes at a time. */ -#ifdef __GCC_ASM_FLAG_OUTPUTS__ - while (1) + typedef v16qi v16qi_u __attribute__ ((__aligned__ (1))); + /* Helper vector for pshufb-based matching: + each character C we're searching for is at position (C % 16). */ + v16qi lut = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, '\\', '\r', 0, '?' }; + static_assert('\n' == 10 && '\r' == 13 && '\\' == 92 && '?' == 63, + "host character encoding is ASCII"); + + v16qi d1, d2, t1, t2; + /* Unaligned loads, potentially using padding after the final newline. */ + static_assert (CPP_BUFFER_PADDING >= 64, ""); + d1 = *(const v16qi_u *)s; + d2 = *(const v16qi_u *)(s + 16); + unsigned m1, m2, found; + /* Process two 16-byte chunks per iteration. */ + do { - char f; - - /* By using inline assembly instead of the builtin, - we can use the result, as well as the flags set. */ - __asm ("%vpcmpestri\t$0, %2, %3" - : "=c"(index), "=@ccc"(f) - : "m"(*s), "x"(search), "a"(4), "d"(16)); - if (f) - break; - - s += 16; + t1 = __builtin_ia32_pshufb128 (lut, d1); + t2 = __builtin_ia32_pshufb128 (lut, d2); + m1 = __builtin_ia32_pmovmskb128 (t1 == d1); + m2 = __builtin_ia32_pmovmskb128 (t2 == d2); + s += 32; + d1 = *(const v16qi_u *)s; + d2 = *(const v16qi_u *)(s + 16); + found = m1 + (m2 << 16); } -#else - s -= 16; - /* By doing the whole loop in inline assembly, - we can make proper use of the flags set. */ - __asm ( ".balign 16\n" - "0: add $16, %1\n" - " %vpcmpestri\t$0, (%1), %2\n" - " jnc 0b" - : "=&c"(index), "+r"(s) - : "x"(search), "a"(4), "d"(16)); -#endif - - found: - return s + index; + while (!found); + /* Prefer to compute 's - 32' here, not spend an extra instruction + to make a copy of the previous value of 's' in the loop. */ + __asm__ ("" : "+r"(s)); + return s - 32 + __builtin_ctz (found); } #else -/* Work around out-dated assemblers without sse4 support. */ -#define search_line_sse42 search_line_sse2 +/* Work around out-dated assemblers without SSSE3 support. */ +#define search_line_ssse3 search_line_sse2 #endif +#ifdef __SSSE3__ +/* No need for CPU probing, just use the best available variant. */ +#define search_line_fast search_line_ssse3 +#else /* Check the CPU capabilities. */ #include "../gcc/config/i386/cpuid.h" typedef const uchar * (*search_line_fast_type) (const uchar *, const uchar *); -static search_line_fast_type search_line_fast; +static search_line_fast_type search_line_fast +#if defined(__SSE2__) + = search_line_sse2; +#else + = search_line_acc_char; +#endif #define HAVE_init_vectorized_lexer 1 static inline void init_vectorized_lexer (void) { - unsigned dummy, ecx = 0, edx = 0; - search_line_fast_type impl = search_line_acc_char; - int minimum = 0; - -#if defined(__SSE4_2__) - minimum = 3; -#elif defined(__SSE2__) - minimum = 2; -#elif defined(__SSE__) - minimum = 1; -#endif + unsigned ax, bx, cx, dx; - if (minimum == 3) - impl = search_line_sse42; - else if (__get_cpuid (1, &dummy, &dummy, &ecx, &edx) || minimum == 2) - { - if (minimum == 3 || (ecx & bit_SSE4_2)) - impl = search_line_sse42; - else if (minimum == 2 || (edx & bit_SSE2)) - impl = search_line_sse2; - else if (minimum == 1 || (edx & bit_SSE)) - impl = search_line_mmx; - } - else if (__get_cpuid (0x80000001, &dummy, &dummy, &dummy, &edx)) - { - if (minimum == 1 - || (edx & (bit_MMXEXT | bit_CMOV)) == (bit_MMXEXT | bit_CMOV)) - impl = search_line_mmx; - } + if (!__get_cpuid (1, &ax, &bx, &cx, &dx)) + return; - search_line_fast = impl; + if (cx & bit_SSSE3) + search_line_fast = search_line_ssse3; + else if (dx & bit_SSE2) + search_line_fast = search_line_sse2; } +#endif #elif (GCC_VERSION >= 4005) && defined(_ARCH_PWR8) && defined(__ALTIVEC__) @@ -1970,11 +1856,12 @@ skip_whitespace (cpp_reader *pfile, cppchar_t c) /* Just \f \v or \0 left. */ else if (c == '\0') saw_NUL = true; - else if (pfile->state.in_directive && CPP_PEDANTIC (pfile)) - cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, - CPP_BUF_COL (buffer), - "%s in preprocessing directive", - c == '\f' ? "form feed" : "vertical tab"); + else if (pfile->state.in_directive) + cpp_pedwarning_with_line (pfile, CPP_W_PEDANTIC, + pfile->line_table->highest_line, + CPP_BUF_COL (buffer), + "%s in preprocessing directive", + c == '\f' ? "form feed" : "vertical tab"); c = *buffer->cur++; } @@ -2140,11 +2027,11 @@ maybe_va_opt_error (cpp_reader *pfile) if (!_cpp_in_system_header (pfile)) { if (CPP_OPTION (pfile, cplusplus)) - cpp_error (pfile, CPP_DL_PEDWARN, - "__VA_OPT__ is not available until C++20"); + cpp_pedwarning (pfile, CPP_W_CXX20_EXTENSIONS, + "__VA_OPT__ is not available until C++20"); else - cpp_error (pfile, CPP_DL_PEDWARN, - "__VA_OPT__ is not available until C23"); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "__VA_OPT__ is not available until C23"); } } else if (!pfile->state.va_args_ok) @@ -4017,8 +3904,9 @@ _cpp_lex_direct (cpp_reader *pfile) && CPP_PEDANTIC (pfile) && ! buffer->warned_cplusplus_comments) { - if (cpp_error (pfile, CPP_DL_PEDWARN, - "C++ style comments are not allowed in ISO C90")) + if (cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "C++ style comments are not allowed " + "in ISO C90")) cpp_error (pfile, CPP_DL_NOTE, "(this will be reported only once per input file)"); buffer->warned_cplusplus_comments = 1; @@ -5334,7 +5222,20 @@ cpp_directive_only_process (cpp_reader *pfile, error messages. */ buffer->line_base -= pos - line_start; - _cpp_handle_directive (pfile, line_start + 1 != pos); + if (_cpp_handle_directive (pfile, line_start + 1 != pos) == 2) + { + if (pfile->directive_result.type != CPP_PADDING) + cb (pfile, CPP_DO_token, data, + &pfile->directive_result, pfile->directive_result.src_loc); + if (pfile->context->prev) + { + gcc_assert (pfile->context->tokens_kind == TOKENS_KIND_DIRECT); + for (const cpp_token *tok = FIRST (pfile->context).token; + tok != LAST (pfile->context).token; ++tok) + cb (pfile, CPP_DO_token, data, tok, tok->src_loc); + _cpp_pop_context (pfile); + } + } /* Sanitize the line settings. Duplicate #include's can mess things up. */ diff --git a/libcpp/macro.cc b/libcpp/macro.cc index 352eb2e..056b38e 100644 --- a/libcpp/macro.cc +++ b/libcpp/macro.cc @@ -371,8 +371,8 @@ unsigned num_macro_tokens_counter = 0; /* Wrapper around cpp_get_token to skip CPP_PADDING tokens and not consume CPP_EOF. */ -static const cpp_token * -cpp_get_token_no_padding (cpp_reader *pfile) +const cpp_token * +_cpp_get_token_no_padding (cpp_reader *pfile) { for (;;) { @@ -385,32 +385,32 @@ cpp_get_token_no_padding (cpp_reader *pfile) } } -/* Handle meeting "__has_include" builtin macro. */ +/* Helper function for builtin_has_include and builtin_has_embed. */ -static int -builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next) +static char * +builtin_has_include_1 (cpp_reader *pfile, const char *name, bool *paren, + bool *bracket, location_t *loc) { - int result = 0; - if (!pfile->state.in_directive) cpp_error (pfile, CPP_DL_ERROR, - "\"%s\" used outside of preprocessing directive", - NODE_NAME (op)); + "\"%s\" used outside of preprocessing directive", name); pfile->state.angled_headers = true; const auto sav_padding = pfile->state.directive_wants_padding; pfile->state.directive_wants_padding = true; - const cpp_token *token = cpp_get_token_no_padding (pfile); - bool paren = token->type == CPP_OPEN_PAREN; - if (paren) - token = cpp_get_token_no_padding (pfile); + const cpp_token *token = _cpp_get_token_no_padding (pfile); + *paren = token->type == CPP_OPEN_PAREN; + if (*paren) + token = _cpp_get_token_no_padding (pfile); else cpp_error (pfile, CPP_DL_ERROR, - "missing '(' before \"%s\" operand", NODE_NAME (op)); + "missing '(' before \"%s\" operand", name); pfile->state.angled_headers = false; pfile->state.directive_wants_padding = sav_padding; - bool bracket = token->type != CPP_STRING; + if (loc) + *loc = token->src_loc; + *bracket = token->type != CPP_STRING; char *fname = NULL; if (token->type == CPP_STRING || token->type == CPP_HEADER_NAME) { @@ -422,7 +422,19 @@ builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next) fname = _cpp_bracket_include (pfile); else cpp_error (pfile, CPP_DL_ERROR, - "operator \"%s\" requires a header-name", NODE_NAME (op)); + "operator \"%s\" requires a header-name", name); + return fname; +} + +/* Handle meeting "__has_include" builtin macro. */ + +static int +builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next) +{ + int result = 0; + bool paren, bracket; + char *fname = builtin_has_include_1 (pfile, (const char *) NODE_NAME (op), + &paren, &bracket, NULL); if (fname) { @@ -437,13 +449,72 @@ builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next) } if (paren - && cpp_get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) + && _cpp_get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"%s\" operand", NODE_NAME (op)); return result; } +/* Handle the "__has_embed" expression. */ + +static int +builtin_has_embed (cpp_reader *pfile) +{ + int result = 0; + bool paren, bracket; + struct cpp_embed_params params = {}; + char *fname = builtin_has_include_1 (pfile, "__has_embed", &paren, + &bracket, ¶ms.loc); + + if (fname) + { + params.has_embed = true; + auto save_in_directive = pfile->state.in_directive; + auto save_angled_headers = pfile->state.angled_headers; + auto save_directive_wants_padding = pfile->state.directive_wants_padding; + auto save_op_stack = pfile->op_stack; + auto save_op_limit = pfile->op_limit; + auto save_skip_eval = pfile->state.skip_eval; + auto save_mi_ind_cmacro = pfile->mi_ind_cmacro; + /* Tell the lexer this is an embed directive. */ + pfile->state.in_directive = 3; + pfile->state.angled_headers = false; + pfile->state.directive_wants_padding = false; + pfile->op_stack = NULL; + pfile->op_limit = NULL; + bool ok = _cpp_parse_embed_params (pfile, ¶ms); + free (pfile->op_stack); + pfile->state.in_directive = save_in_directive; + pfile->state.angled_headers = save_angled_headers; + pfile->state.directive_wants_padding = save_directive_wants_padding; + pfile->op_stack = save_op_stack; + pfile->op_limit = save_op_limit; + pfile->state.skip_eval = save_skip_eval; + pfile->mi_ind_cmacro = save_mi_ind_cmacro; + + if (!*fname) + { + cpp_error_with_line (pfile, CPP_DL_ERROR, params.loc, 0, + "empty filename in '%s'", "__has_embed"); + ok = false; + } + + /* Do not do the lookup if we're skipping, that's unnecessary + IO. */ + if (ok && !pfile->state.skip_eval) + result = _cpp_stack_embed (pfile, fname, bracket, ¶ms); + + _cpp_free_embed_params_tokens (¶ms.base64); + + XDELETEVEC (fname); + } + else if (paren) + _cpp_get_token_no_padding (pfile); + + return result; +} + /* Emits a warning if NODE is a macro defined in the main file that has not been used. */ int @@ -681,6 +752,16 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node, node->value.builtin == BT_HAS_INCLUDE_NEXT); break; + case BT_HAS_EMBED: + if (CPP_OPTION (pfile, traditional)) + { + cpp_error (pfile, CPP_DL_ERROR, /* FIXME should be DL_SORRY */ + "'__has_embed' not supported in traditional C"); + break; + } + number = builtin_has_embed (pfile); + break; + case BT_HAS_FEATURE: case BT_HAS_EXTENSION: number = pfile->cb.has_feature (pfile, @@ -1117,13 +1198,13 @@ _cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node && ! CPP_OPTION (pfile, va_opt)) { if (CPP_OPTION (pfile, cplusplus)) - cpp_error (pfile, CPP_DL_PEDWARN, - "ISO C++11 requires at least one argument " - "for the \"...\" in a variadic macro"); + cpp_pedwarning (pfile, CPP_W_CXX20_EXTENSIONS, + "ISO C++11 requires at least one argument " + "for the \"...\" in a variadic macro"); else - cpp_error (pfile, CPP_DL_PEDWARN, - "ISO C99 requires at least one argument " - "for the \"...\" in a variadic macro"); + cpp_pedwarning (pfile, CPP_W_PEDANTIC, + "ISO C99 requires at least one argument " + "for the \"...\" in a variadic macro"); } return true; } @@ -2312,7 +2393,7 @@ replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, && ! macro->syshdr && ! _cpp_in_system_header (pfile)) { if (CPP_OPTION (pfile, cplusplus)) - cpp_pedwarning (pfile, CPP_W_PEDANTIC, + cpp_pedwarning (pfile, CPP_W_VARIADIC_MACROS, "invoking macro %s argument %d: " "empty macro arguments are undefined" " in ISO C++98", diff --git a/libcpp/po/ChangeLog b/libcpp/po/ChangeLog index bfaa057..79e1c72 100644 --- a/libcpp/po/ChangeLog +++ b/libcpp/po/ChangeLog @@ -1,3 +1,7 @@ +2024-09-19 Joseph Myers <josmyers@redhat.com> + + * zh_CN.po: Update. + 2024-02-21 Joseph Myers <josmyers@redhat.com> * de.po: Update. diff --git a/libcpp/po/zh_CN.po b/libcpp/po/zh_CN.po index 7c7c4d9..bc9c734 100644 --- a/libcpp/po/zh_CN.po +++ b/libcpp/po/zh_CN.po @@ -2,22 +2,22 @@ # Copyright (C) 2005 Free Software Foundation, Inc. # This file is distributed under the same license as the gcc package. # Meng Jie <zuxy.meng@gmail.com>, 2005-2010. +# Zhanhaoxiang Zhang <zzhx2006@outlook.com>, 2024. # msgid "" msgstr "" -"Project-Id-Version: cpplib 4.6.0\n" +"Project-Id-Version: cpplib 14.1-b20240218\n" "Report-Msgid-Bugs-To: https://gcc.gnu.org/bugs/\n" "POT-Creation-Date: 2024-02-16 21:34+0000\n" -"PO-Revision-Date: 2011-05-12 17:23+0800\n" -"Last-Translator: Meng Jie <zuxy.meng@gmail.com>\n" +"PO-Revision-Date: 2024-09-16 08:23+0800\n" +"Last-Translator: Zhanhaoxiang Zhang <zzhx2006@outlook.com>\n" "Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Bugs: Report translation errors to the Language-Team address.\n" -"X-Poedit-Language: Chinese\n" -"X-Poedit-Country: CHINA\n" +"X-Generator: Poedit 3.4.2\n" #: charset.cc:759 #, c-format @@ -52,10 +52,8 @@ msgid "universal character names are only valid in C++ and C99" msgstr "Unicode 字符名只在 C++ 和 C99 中有效" #: charset.cc:1553 -#, fuzzy -#| msgid "universal character names are only valid in C++ and C99" msgid "C99's universal character names are incompatible with C90" -msgstr "Unicode 字符名只在 C++ 和 C99 中有效" +msgstr "C99 的 Unicode 字符名与 C90 不兼容" #: charset.cc:1556 #, c-format @@ -63,53 +61,45 @@ msgid "the meaning of '\\%c' is different in traditional C" msgstr "‘\\%c’的意义与在传统 C 中不同" #: charset.cc:1595 -#, fuzzy -#| msgid "'?' without following ':'" msgid "'\\N' not followed by '{'" -msgstr "‘?’后没有‘:’" +msgstr "‘\\N’后没有‘{’" #: charset.cc:1625 msgid "empty named universal character escape sequence; treating it as separate tokens" -msgstr "" +msgstr "空的命名 Unicode 字符转义序列;将其视为独立 token 处理" #: charset.cc:1632 -#, fuzzy -#| msgid "incomplete universal character name %.*s" msgid "empty named universal character escape sequence" -msgstr "不完全的 Unicode 字符名 %.*s" +msgstr "空的命名 Unicode 字符转义序列" #: charset.cc:1637 -#, fuzzy -#| msgid "universal character names are only valid in C++ and C99" msgid "named universal character escapes are only valid in C++23" -msgstr "Unicode 字符名只在 C++ 和 C99 中有效" +msgstr "命名 Unicode 字符转义序列(named universal character escapes)仅在 C++23 中有效" #: charset.cc:1657 -#, fuzzy, c-format -#| msgid "%.*s is not a valid universal character" +#, c-format msgid "\\N{%.*s} is not a valid universal character; treating it as separate tokens" -msgstr "%.*s 不是一个有效的 Unicode 字符" +msgstr "\\N{%.*s} 不是一个有效的 Unicode 字符;将其视为独立 token 处理" #: charset.cc:1663 -#, fuzzy, c-format -#| msgid "%.*s is not a valid universal character" +#, c-format msgid "\\N{%.*s} is not a valid universal character" -msgstr "%.*s 不是一个有效的 Unicode 字符" +msgstr "\\N{%.*s} 不是一个有效的 Unicode 字符" #: charset.cc:1673 #, c-format msgid "did you mean \\N{%s}?" -msgstr "" +msgstr "你是说 \\N{%s} 吗?" #: charset.cc:1691 #, c-format msgid "'\\N{' not terminated with '}' after %.*s; treating it as separate tokens" -msgstr "" +msgstr "在 %.*s 之后 '\\N{' 未以 '}' 结束;将其视为独立 token 处理" #: charset.cc:1700 #, c-format msgid "'\\N{' not terminated with '}' after %.*s" -msgstr "" +msgstr "在 %.*s 之后 '\\N{' 未以 '}' 结束" #: charset.cc:1708 msgid "In _cpp_valid_ucn but not a UCN" @@ -117,22 +107,20 @@ msgstr "在 _cpp_valid_ucn 中但不是一个 UCN" #: charset.cc:1750 msgid "empty delimited escape sequence; treating it as separate tokens" -msgstr "" +msgstr "空的带分隔符的转义序列;将其视为独立 token 处理" #: charset.cc:1757 charset.cc:2124 charset.cc:2227 msgid "empty delimited escape sequence" -msgstr "" +msgstr "空的带分隔符的转义序列" #: charset.cc:1761 charset.cc:2130 charset.cc:2233 -#, fuzzy -#| msgid "universal character names are only valid in C++ and C99" msgid "delimited escape sequences are only valid in C++23" -msgstr "Unicode 字符名只在 C++ 和 C99 中有效" +msgstr "带分隔符的转义序列仅在 C++23 中有效" #: charset.cc:1775 #, c-format msgid "'\\u{' not terminated with '}' after %.*s; treating it as separate tokens" -msgstr "" +msgstr "在 %.*s 之后 '\\u{' 未以 '}' 结束;将其视为独立 token 处理" #: charset.cc:1787 #, c-format @@ -142,7 +130,7 @@ msgstr "不完全的 Unicode 字符名 %.*s" #: charset.cc:1791 #, c-format msgid "'\\u{' not terminated with '}' after %.*s" -msgstr "" +msgstr "在 %.*s 之后 '\\u{' 未以 '}' 结束" #: charset.cc:1806 #, c-format @@ -166,7 +154,7 @@ msgstr "Unicode 字符 %.*s 在标识符开头无效" #: charset.cc:1837 #, c-format msgid "%.*s is outside the UCS codespace" -msgstr "" +msgstr "%.*s 超出了 UCS 码空间" #: charset.cc:1881 charset.cc:3037 msgid "converting UCN to source character set" @@ -177,16 +165,14 @@ msgid "converting UCN to execution character set" msgstr "将 UCN 转换到执行字符集" #: charset.cc:1952 -#, fuzzy, c-format -#| msgid "universal character %.*s is not valid in an identifier" +#, c-format msgid "extended character %.*s is not valid in an identifier" -msgstr "Unicode 字符 %.*s 在标识符中无效" +msgstr "扩展字符 %.*s 在标识符中无效" #: charset.cc:1969 -#, fuzzy, c-format -#| msgid "universal character %.*s is not valid at the start of an identifier" +#, c-format msgid "extended character %.*s is not valid at the start of an identifier" -msgstr "Unicode 字符 %.*s 在标识符开头无效" +msgstr "扩展字符 %.*s 在标识符开头无效" #: charset.cc:2091 msgid "the meaning of '\\x' is different in traditional C" @@ -199,22 +185,20 @@ msgstr "\\x 后没有 16 进制数字" #: charset.cc:2144 #, c-format msgid "'\\x{' not terminated with '}' after %.*s" -msgstr "" +msgstr "在 %.*s 之后 '\\x{' 未以 '}' 结束" #: charset.cc:2152 msgid "hex escape sequence out of range" msgstr "16 进制转义序列越界" #: charset.cc:2195 -#, fuzzy -#| msgid "'?' without following ':'" msgid "'\\o' not followed by '{'" -msgstr "‘?’后没有‘:’" +msgstr "‘\\o’后没有‘{’" #: charset.cc:2239 #, c-format msgid "'\\o{' not terminated with '}' after %.*s" -msgstr "" +msgstr "在 %.*s 之后 '\\o{' 未以 '}' 结束" #: charset.cc:2248 msgid "octal escape sequence out of range" @@ -223,7 +207,7 @@ msgstr "8 进制转义序列越界" #: charset.cc:2300 charset.cc:2310 #, c-format msgid "numeric escape sequence in unevaluated string: '\\%c'" -msgstr "" +msgstr "数值转义序列在未求值的字符串中:‘%c’" #: charset.cc:2338 msgid "the meaning of '\\a' is different in traditional C" @@ -250,30 +234,28 @@ msgstr "将转义序列转换到执行字符集" #: charset.cc:2511 msgid "missing open quote" -msgstr "" +msgstr "缺少开引号" #: charset.cc:2772 -#, fuzzy -#| msgid "character 0x%lx is not unibyte in execution character set" msgid "character not encodable in a single execution character code unit" -msgstr "字符 0x%lx 在执行字符集中不是单字节的" +msgstr "字符无法在单个执行字符码元中编码" #: charset.cc:2777 msgid "at least one character in a multi-character literal not encodable in a single execution character code unit" -msgstr "" +msgstr "在多字符字面量中至少有一个字符无法在一个单独的执行字符码元中编码" #: charset.cc:2795 #, c-format msgid "multi-character literal with %ld characters exceeds 'int' size of %ld bytes" -msgstr "" +msgstr "带有 %ld 个字符的多字符字面量超过了 ‘int’ 的大小,即 %ld 字节" #: charset.cc:2799 charset.cc:2894 msgid "multi-character literal cannot have an encoding prefix" -msgstr "" +msgstr "多字符字面量不能有编码前缀" #: charset.cc:2802 charset.cc:2897 msgid "character not encodable in a single code unit" -msgstr "" +msgstr "字符无法在单个码元中编码" #: charset.cc:2806 msgid "multi-character character constant" @@ -299,16 +281,14 @@ msgid "#%s is a GCC extension" msgstr "#%s 是一个 GCC 扩展" #: directives.cc:394 directives.cc:2163 directives.cc:2202 -#, fuzzy, c-format -#| msgid "#%s is a GCC extension" +#, c-format msgid "#%s before C++23 is a GCC extension" -msgstr "#%s 是一个 GCC 扩展" +msgstr "#%s 在C++23以前是一个 GCC 扩展" #: directives.cc:397 directives.cc:401 directives.cc:2167 directives.cc:2206 -#, fuzzy, c-format -#| msgid "#%s is a GCC extension" +#, c-format msgid "#%s before C23 is a GCC extension" -msgstr "#%s 是一个 GCC 扩展" +msgstr "#%s 在C23以前是一个 GCC 扩展" #: directives.cc:407 #, c-format @@ -338,10 +318,9 @@ msgid "style of line directive is a GCC extension" msgstr "line 指示的风格是一个 GCC 扩展" #: directives.cc:556 -#, fuzzy, c-format -#| msgid "invalid preprocessing directive #%s" +#, c-format msgid "invalid preprocessing directive #%s; did you mean #%s?" -msgstr "无效的预处理指示 #%s" +msgstr "无效的预处理指令 #%s;你是说 #%s 吗?" #: directives.cc:562 #, c-format @@ -349,10 +328,9 @@ msgid "invalid preprocessing directive #%s" msgstr "无效的预处理指示 #%s" #: directives.cc:632 -#, fuzzy, c-format -#| msgid "\"defined\" cannot be used as a macro name" +#, c-format msgid "\"%s\" cannot be used as a macro name" -msgstr "“defined”不能被用作宏名" +msgstr "“%s”不能被用作宏名" #: directives.cc:639 #, c-format @@ -390,7 +368,7 @@ msgstr "#%s 中文件名为空" #: directives.cc:873 #, c-format msgid "#include nested depth %u exceeds maximum of %u (use -fmax-include-depth=DEPTH to increase the maximum)" -msgstr "" +msgstr "#include 嵌套深度 %u 超出了最大值 %u(使用 -fmax-include-depth=DEPTH 来增加最大值)" #: directives.cc:918 msgid "#include_next in primary source file" @@ -427,7 +405,7 @@ msgstr "# 后的“%s”不是一个正整数" #: directives.cc:1143 #, c-format msgid "file \"%s\" linemarker ignored due to incorrect nesting" -msgstr "" +msgstr "文件 “%s” 中的行标记因嵌套不正确而被忽略" #: directives.cc:1221 directives.cc:1223 directives.cc:1225 directives.cc:1816 #, c-format @@ -504,10 +482,9 @@ msgid "current file is older than %s" msgstr "当前文件早于 %s" #: directives.cc:1811 -#, fuzzy, c-format -#| msgid "invalid #pragma GCC poison directive" +#, c-format msgid "invalid \"#pragma GCC %s\" directive" -msgstr "无效的 #pragma GCC poison 指示" +msgstr "无效的 #pragma GCC %s 指示" #: directives.cc:2019 msgid "_Pragma takes a parenthesized string literal" @@ -526,16 +503,14 @@ msgid "the conditional began here" msgstr "条件自此开始" #: directives.cc:2135 -#, fuzzy, c-format -#| msgid "#else without #if" +#, c-format msgid "#%s without #if" -msgstr "#else 没有匹配的 #if" +msgstr "#%s 没有匹配的 #if" #: directives.cc:2140 -#, fuzzy, c-format -#| msgid "#else after #else" +#, c-format msgid "#%s after #else" -msgstr "#else 出现在 #else 后" +msgstr "#%s 出现在 #else 后" #: directives.cc:2242 msgid "#endif without #if" @@ -589,10 +564,8 @@ msgid "invalid prefix \"0b\" for floating constant" msgstr "浮点常量的“0b”前缀无效" #: expr.cc:705 -#, fuzzy -#| msgid "use of C99 hexadecimal floating constant" msgid "use of C++17 hexadecimal floating constant" -msgstr "使用 C99 式的 16 进制浮点常量" +msgstr "使用 C++17 式的 16 进制浮点常量" #: expr.cc:708 msgid "use of C99 hexadecimal floating constant" @@ -618,10 +591,8 @@ msgid "invalid suffix \"%.*s\" with hexadecimal floating constant" msgstr "十六进制浮点常量的“%.*s”后缀无效" #: expr.cc:790 expr.cc:794 -#, fuzzy -#| msgid "decimal float constants are a GCC extension" msgid "decimal float constants are a C23 feature" -msgstr "十进制浮点常量是一个 GCC 扩展" +msgstr "十进制浮点常量是一个 C23 特性" #: expr.cc:813 #, c-format @@ -629,52 +600,40 @@ msgid "invalid suffix \"%.*s\" on integer constant" msgstr "整数常量的“%.*s”后缀无效" #: expr.cc:838 -#, fuzzy -#| msgid "use of C++0x long long integer constant" msgid "use of C++11 long long integer constant" -msgstr "使用 C++0x long long 整数常量" +msgstr "使用 C++11 long long 整数常量" #: expr.cc:839 msgid "use of C99 long long integer constant" msgstr "使用 C99 long long 整数常量" #: expr.cc:853 -#, fuzzy -#| msgid "use of C++0x long long integer constant" msgid "use of C++23 %<size_t%> integer constant" -msgstr "使用 C++0x long long 整数常量" +msgstr "使用 C++23 %<size_t%> 整数常量" #: expr.cc:854 -#, fuzzy -#| msgid "use of C++0x long long integer constant" msgid "use of C++23 %<make_signed_t<size_t>%> integer constant" -msgstr "使用 C++0x long long 整数常量" +msgstr "使用 C++23 %<make_signed_t<size_t>%> 整数常量" #: expr.cc:864 expr.cc:875 msgid "ISO C does not support literal %<wb%> suffixes before C23" -msgstr "" +msgstr "在 C23 之前,ISO C 不支持字面量 %<wb%> 后缀" #: expr.cc:888 msgid "imaginary constants are a GCC extension" msgstr "虚数常量是一个 GCC 扩展" #: expr.cc:895 -#, fuzzy -#| msgid "binary constants are a GCC extension" msgid "binary constants are a C++14 feature or GCC extension" -msgstr "二进制常量是一个 GCC 扩展" +msgstr "二进制常量是一个 C++14 特性或 GCC 扩展" #: expr.cc:897 -#, fuzzy -#| msgid "binary constants are a GCC extension" msgid "binary constants are a C23 feature or GCC extension" -msgstr "二进制常量是一个 GCC 扩展" +msgstr "二进制常量是一个 C23 特性或 GCC 扩展" #: expr.cc:902 -#, fuzzy -#| msgid "binary constants are a GCC extension" msgid "binary constants are a C23 feature" -msgstr "二进制常量是一个 GCC 扩展" +msgstr "二进制常量是一个 C23 特性" #: expr.cc:998 msgid "integer constant is too large for its type" @@ -702,10 +661,8 @@ msgid "this use of \"defined\" may not be portable" msgstr "使用“defined”可能不利于移植" #: expr.cc:1197 -#, fuzzy -#| msgid "integer overflow in preprocessor expression" msgid "user-defined literal in preprocessor expression" -msgstr "预处理表达式中整数溢出" +msgstr "预处理表达式中的用户定义字面量" #: expr.cc:1202 msgid "floating constant in preprocessor expression" @@ -716,10 +673,9 @@ msgid "imaginary number in preprocessor expression" msgstr "预处理表达式中出现虚数" #: expr.cc:1257 -#, fuzzy, c-format -#| msgid "\"%s\" is not defined" +#, c-format msgid "\"%s\" is not defined, evaluates to 0" -msgstr "“%s”未定义" +msgstr "\"%s\" 未定义,计算结果为 0" #: expr.cc:1270 msgid "assertions are a GCC extension" @@ -867,50 +823,50 @@ msgstr "三元符 ??%c 被忽略,请使用 -trigraphs 来启用" #: lex.cc:1610 msgid "end of bidirectional context" -msgstr "" +msgstr "双向上下文的结束" #: lex.cc:1651 msgid "unpaired UTF-8 bidirectional control characters detected" -msgstr "" +msgstr "检测到未配对的 UTF-8 双向控制字符" #: lex.cc:1655 msgid "unpaired UTF-8 bidirectional control character detected" -msgstr "" +msgstr "检测到未配对的 UTF-8 双向控制字符" #: lex.cc:1693 #, c-format msgid "UTF-8 vs UCN mismatch when closing a context by \"%s\"" -msgstr "" +msgstr "通过 “%s” 关闭上下文时,UTF-8 与 UCN 不匹配" #: lex.cc:1702 #, c-format msgid "\"%s\" is closing an unopened context" -msgstr "" +msgstr "“%s” 正在关闭一个未打开的上下文" #: lex.cc:1706 #, c-format msgid "found problematic Unicode character \"%s\"" -msgstr "" +msgstr "发现了有问题的 Unicode 字符 “%s”" #: lex.cc:1736 lex.cc:1742 #, c-format msgid "invalid UTF-8 character <%x>" -msgstr "" +msgstr "无效的 UTF-8 字符 <%x>" #: lex.cc:1752 lex.cc:1758 #, c-format msgid "invalid UTF-8 character <%x><%x>" -msgstr "" +msgstr "无效的 UTF-8 字符 <%x><%x>" #: lex.cc:1768 lex.cc:1774 #, c-format msgid "invalid UTF-8 character <%x><%x><%x>" -msgstr "" +msgstr "无效的 UTF-8 字符 <%x><%x><%x>" #: lex.cc:1784 lex.cc:1790 #, c-format msgid "invalid UTF-8 character <%x><%x><%x><%x>" -msgstr "" +msgstr "无效的 UTF-8 字符 <%x><%x><%x><%x>" #: lex.cc:1872 msgid "\"/*\" within comment" @@ -937,17 +893,15 @@ msgstr "‘%.*s’不在 NFC 中" #: lex.cc:2144 msgid "__VA_OPT__ is not available until C++20" -msgstr "" +msgstr "__VA_OPT__ 直到 C++20 才可用" #: lex.cc:2147 msgid "__VA_OPT__ is not available until C23" -msgstr "" +msgstr "__VA_OPT__ 直到 C23 才可用" #: lex.cc:2155 -#, fuzzy -#| msgid "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro" msgid "__VA_OPT__ can only appear in the expansion of a C++20 variadic macro" -msgstr "__VA_ARGS__ 只能出现在 C99 可变参数宏的展开中" +msgstr "__VA_OPT__ 只能出现在 C++20 可变参数宏的展开中" #: lex.cc:2172 #, c-format @@ -956,13 +910,11 @@ msgstr "试图使用有毒的“%s”" #: lex.cc:2177 msgid "poisoned here" -msgstr "" +msgstr "在此处被毒化" #: lex.cc:2187 -#, fuzzy -#| msgid "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro" msgid "__VA_ARGS__ can only appear in the expansion of a C++11 variadic macro" -msgstr "__VA_ARGS__ 只能出现在 C99 可变参数宏的展开中" +msgstr "__VA_ARGS__ 只能出现在 C++11 可变参数宏的展开中" #: lex.cc:2191 msgid "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro" @@ -975,21 +927,19 @@ msgstr "标识符“%s”是 C++ 中的一个特殊操作符" #: lex.cc:2372 msgid "adjacent digit separators" -msgstr "" +msgstr "相邻的数字分隔符" #: lex.cc:2521 msgid "invalid suffix on literal; C++11 requires a space between literal and string macro" -msgstr "" +msgstr "字面量后缀无效;C++11 要求字面量和字符串宏之间必须有空格" #: lex.cc:2729 msgid "raw string delimiter longer than 16 characters" msgstr "原始字符串分隔符长过 16 个字符" #: lex.cc:2733 -#, fuzzy -#| msgid "invalid character '%c' in raw string delimiter" msgid "invalid new-line in raw string delimiter" -msgstr "原始字符串分隔符中有无效字符‘%c’" +msgstr "原始字符串分隔符中有无效的换行符" #: lex.cc:2737 lex.cc:5576 #, c-format @@ -1011,16 +961,16 @@ msgstr "缺少结尾的 %c 字符" #: lex.cc:2991 msgid "C++11 requires a space between string literal and macro" -msgstr "" +msgstr "C++11 要求字符串字面量和宏之间必须有空格" #: lex.cc:3584 msgid "module control-line cannot be in included file" -msgstr "" +msgstr "模块控制行不能位于被包含的文件中" #: lex.cc:3598 #, c-format msgid "module control-line \"%s\" cannot be an object-like macro" -msgstr "" +msgstr "模块控制行 “%s” 不能是一个对象宏" #: lex.cc:4004 lex.cc:5409 traditional.cc:174 msgid "unterminated comment" @@ -1035,10 +985,8 @@ msgid "(this will be reported only once per input file)" msgstr "(此警告为每个输入文件只报告一次)" #: lex.cc:4029 -#, fuzzy -#| msgid "C++ style comments are not allowed in ISO C90" msgid "C++ style comments are incompatible with C90" -msgstr "C++ 风格的注释在 ISO C90 中不被允许" +msgstr "C++ 风格的注释与 C90 不兼容" #: lex.cc:4061 msgid "multi-line comment" @@ -1050,60 +998,49 @@ msgid "unspellable token %s" msgstr "无法拼出的标识符 %s" #: lex.cc:5564 -#, fuzzy, c-format -#| msgid "raw string delimiter longer than 16 characters" +#, c-format msgid "raw string delimiter longer than %d characters" -msgstr "原始字符串分隔符长过 16 个字符" +msgstr "原始字符串分隔符长过 %d 个字符" #: lex.cc:5634 -#, fuzzy -#| msgid "unterminated #%s" msgid "unterminated literal" -msgstr "未终止的 #%s" +msgstr "未终止的字面量" #: macro.cc:94 -#, fuzzy -#| msgid "'##' cannot appear at either end of a macro expansion" msgid "'##' cannot appear at either end of __VA_OPT__" -msgstr "‘##’不能出现在宏展开的两端" +msgstr "‘##’不能出现在__VA_OPT__的两端" #: macro.cc:144 msgid "__VA_OPT__ may not appear in a __VA_OPT__" -msgstr "" +msgstr "__VA_OPT__ 不能出现在另一个 __VA_OPT__ 中" #: macro.cc:157 msgid "__VA_OPT__ must be followed by an open parenthesis" -msgstr "" +msgstr "__VA_OPT__ 后面必须跟一个开括号" #: macro.cc:235 -#, fuzzy -#| msgid "unterminated #%s" msgid "unterminated __VA_OPT__" -msgstr "未终止的 #%s" +msgstr "未终止的 __VA_OPT__" #: macro.cc:397 -#, fuzzy, c-format -#| msgid "%s in preprocessing directive" +#, c-format msgid "\"%s\" used outside of preprocessing directive" -msgstr "预处理指示中出现 %s" +msgstr "\"%s\" 在预处理指令外部使用" #: macro.cc:407 -#, fuzzy, c-format -#| msgid "missing '(' in expression" +#, c-format msgid "missing '(' before \"%s\" operand" -msgstr "表达式中缺少‘(’" +msgstr "操作数“%s”之前缺少 ‘(’" #: macro.cc:422 -#, fuzzy, c-format -#| msgid "operator \"defined\" requires an identifier" +#, c-format msgid "operator \"%s\" requires a header-name" -msgstr "操作符“defined”需要一个标识符" +msgstr "运算符 “%s” 需要一个头文件名" #: macro.cc:439 -#, fuzzy, c-format -#| msgid "missing ')' after \"defined\"" +#, c-format msgid "missing ')' after \"%s\" operand" -msgstr "“defined” 后出现‘)’" +msgstr "操作数“%s”之后缺少 ‘)’" #: macro.cc:459 #, c-format @@ -1118,7 +1055,7 @@ msgstr "无效的内建宏“%s”" #: macro.cc:505 macro.cc:613 #, c-format msgid "macro \"%s\" might prevent reproducible builds" -msgstr "" +msgstr "宏 “%s” 可能会阻止可重现构建" #: macro.cc:536 msgid "could not determine file timestamp" @@ -1137,20 +1074,17 @@ msgid "invalid string literal, ignoring final '\\'" msgstr "无效的字面字符串,忽略最后的‘\\’" #: macro.cc:986 -#, fuzzy, c-format -#| msgid "pasting \"%s\" and \"%s\" does not give a valid preprocessing token" +#, c-format msgid "pasting \"%.*s\" and \"%.*s\" does not give a valid preprocessing token" -msgstr "毗连“%s”和“%s”不能给出一个有效的预处理标识符" +msgstr "毗连“%.*s”和“%.*s”不能给出一个有效的预处理标识符" #: macro.cc:1118 msgid "ISO C++11 requires at least one argument for the \"...\" in a variadic macro" -msgstr "" +msgstr "ISO C++11 要求在可变参数宏中的 “...” 至少有一个参数" #: macro.cc:1122 -#, fuzzy -#| msgid "ISO C99 requires rest arguments to be used" msgid "ISO C99 requires at least one argument for the \"...\" in a variadic macro" -msgstr "ISO C99 需要使用剩余的参数" +msgstr "ISO C99 要求在可变参数宏中的 “...” 至少有一个参数" #: macro.cc:1129 #, c-format @@ -1163,10 +1097,9 @@ msgid "macro \"%s\" passed %u arguments, but takes just %u" msgstr "宏“%s”传递了 %u 个参数,但只需要 %u 个" #: macro.cc:1138 -#, fuzzy, c-format -#| msgid "macro \"%s\" is not used" +#, c-format msgid "macro \"%s\" defined here" -msgstr "宏“%s”未被使用" +msgstr "宏“%s”在此被定义" #: macro.cc:1332 traditional.cc:822 #, c-format @@ -1179,16 +1112,14 @@ msgid "function-like macro \"%s\" must be used with arguments in traditional C" msgstr "类似函数的宏“%s”在传统 C 中必须与参数一起使用" #: macro.cc:2313 -#, fuzzy, c-format -#| msgid "invoking macro %s argument %d: empty macro arguments are undefined in ISO C90 and ISO C++98" +#, c-format msgid "invoking macro %s argument %d: empty macro arguments are undefined in ISO C++98" -msgstr "调用宏 %s 的参数 %d:空的宏参数未被 ISO C90 和 ISO C++98 定义" +msgstr "调用宏 %s 的参数 %d:空的宏参数未被 ISO C++98 定义" #: macro.cc:2321 macro.cc:2330 -#, fuzzy, c-format -#| msgid "invoking macro %s argument %d: empty macro arguments are undefined in ISO C90 and ISO C++98" +#, c-format msgid "invoking macro %s argument %d: empty macro arguments are undefined in ISO C90" -msgstr "调用宏 %s 的参数 %d:空的宏参数未被 ISO C90 和 ISO C++98 定义" +msgstr "调用宏 %s 的参数 %d:空的宏参数未被 ISO C90 定义" #: macro.cc:3381 #, c-format @@ -1198,42 +1129,36 @@ msgstr "重复的宏参数“%s”" #: macro.cc:3463 #, c-format msgid "expected parameter name, found \"%s\"" -msgstr "" +msgstr "预期为参数名称,却发现了 “%s”" #: macro.cc:3464 #, c-format msgid "expected ',' or ')', found \"%s\"" -msgstr "" +msgstr "预期为 ‘,’ 或 ‘)’, 却发现了 “%s”" #: macro.cc:3465 msgid "expected parameter name before end of line" -msgstr "" +msgstr "在行末之前预期为参数名称" #: macro.cc:3466 -#, fuzzy -#| msgid "unexpected end of file after #line" msgid "expected ')' before end of line" -msgstr "#line 后未预期的文件结束" +msgstr "在行末之前预期为 ‘)’" #: macro.cc:3467 msgid "expected ')' after \"...\"" -msgstr "" +msgstr "在 “...” 之后预期为 ‘)’" #: macro.cc:3524 -#, fuzzy -#| msgid "anonymous variadic macros were introduced in C99" msgid "anonymous variadic macros were introduced in C++11" -msgstr "匿名可变参数宏在 C99 中被引入" +msgstr "匿名可变参数宏在 C++11 中被引入" #: macro.cc:3525 macro.cc:3529 msgid "anonymous variadic macros were introduced in C99" msgstr "匿名可变参数宏在 C99 中被引入" #: macro.cc:3535 -#, fuzzy -#| msgid "ISO C does not permit named variadic macros" msgid "ISO C++ does not permit named variadic macros" -msgstr "ISO C 不允许有名的可变参数宏" +msgstr "ISO C++ 不允许有名的可变参数宏" #: macro.cc:3536 msgid "ISO C does not permit named variadic macros" @@ -1244,10 +1169,8 @@ msgid "'##' cannot appear at either end of a macro expansion" msgstr "‘##’不能出现在宏展开的两端" #: macro.cc:3620 -#, fuzzy -#| msgid "ISO C99 requires whitespace after the macro name" msgid "ISO C++11 requires whitespace after the macro name" -msgstr "ISO C99 要求宏名后必须有空白" +msgstr "ISO C++11 要求宏名后必须有空白" #: macro.cc:3621 msgid "ISO C99 requires whitespace after the macro name" |