Mercurial > hg > CbC > CbC_gcc
diff gcc/c-family/c-lex.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | 561a7518be6b |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/c-family/c-lex.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/c-family/c-lex.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,7 +1,5 @@ /* Mainly the interface between cpplib and the C front ends. - Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997 - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + Copyright (C) 1987-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -22,20 +20,15 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" - -#include "tree.h" -#include "input.h" -#include "output.h" +#include "target.h" #include "c-common.h" -#include "flags.h" #include "timevar.h" -#include "cpplib.h" +#include "stringpool.h" +#include "stor-layout.h" #include "c-pragma.h" -#include "intl.h" -#include "splay-tree.h" #include "debug.h" -#include "target.h" + +#include "attribs.h" /* We may keep statistics about how long which files took to compile. */ static int header_time, body_time; @@ -44,13 +37,15 @@ int pending_lang_change; /* If we need to switch languages - C++ only */ int c_header_level; /* depth in C headers - C++ only */ -static tree interpret_integer (const cpp_token *, unsigned int); -static tree interpret_float (const cpp_token *, unsigned int); +static tree interpret_integer (const cpp_token *, unsigned int, + enum overflow_type *); +static tree interpret_float (const cpp_token *, unsigned int, const char *, + enum overflow_type *); static tree interpret_fixed (const cpp_token *, unsigned int); static enum integer_type_kind narrowest_unsigned_type - (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); + (const widest_int &, unsigned int); static enum integer_type_kind narrowest_signed_type - (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, unsigned int); + (const widest_int &, unsigned int); static enum cpp_ttype lex_string (const cpp_token *, tree *, bool, bool); static tree lex_charconst (const cpp_token *); static void update_header_times (const char *); @@ -84,6 +79,9 @@ cb->def_pragma = cb_def_pragma; cb->valid_pch = c_common_valid_pch; cb->read_pch = c_common_read_pch; + cb->has_attribute = c_common_has_attribute; + cb->get_source_date_epoch = cb_get_source_date_epoch; + cb->get_suggestion = cb_get_suggestion; /* Set the debug callbacks if we can use them. */ if ((debug_info_level == DINFO_LEVEL_VERBOSE @@ -146,7 +144,7 @@ void dump_time_statistics (void) { - struct c_fileinfo *file = get_fileinfo (input_filename); + struct c_fileinfo *file = get_fileinfo (LOCATION_FILE (input_location)); int this_time = get_run_time (); file->time += this_time - body_time; @@ -165,18 +163,16 @@ unsigned int ARG_UNUSED (line), const cpp_string * ARG_UNUSED (str)) { -#ifdef ASM_OUTPUT_IDENT if (!flag_no_ident) { /* Convert escapes in the string. */ cpp_string cstr = { 0, 0 }; if (cpp_interpret_string (pfile, str, 1, &cstr, CPP_STRING)) { - ASM_OUTPUT_IDENT (asm_out_file, (const char *) cstr.text); + targetm.asm_out.output_ident ((const char *) cstr.text); free (CONST_CAST (unsigned char *, cstr.text)); } } -#endif } /* Called at the start of every non-empty line. TOKEN is the first @@ -190,7 +186,7 @@ } void -fe_file_change (const struct line_map *new_map) +fe_file_change (const line_map_ordinary *new_map) { if (new_map == NULL) return; @@ -207,11 +203,11 @@ line = SOURCE_LINE (new_map - 1, included_at); input_location = new_map->start_location; - (*debug_hooks->start_source_file) (line, new_map->to_file); + (*debug_hooks->start_source_file) (line, LINEMAP_FILE (new_map)); #ifndef NO_IMPLICIT_EXTERN_C if (c_header_level) ++c_header_level; - else if (new_map->sysp == 2) + else if (LINEMAP_SYSP (new_map) == 2) { c_header_level = 1; ++pending_lang_change; @@ -224,17 +220,17 @@ #ifndef NO_IMPLICIT_EXTERN_C if (c_header_level && --c_header_level == 0) { - if (new_map->sysp == 2) + if (LINEMAP_SYSP (new_map) == 2) warning (0, "badly nested C headers from preprocessor"); --pending_lang_change; } #endif input_location = new_map->start_location; - (*debug_hooks->end_source_file) (new_map->to_line); + (*debug_hooks->end_source_file) (LINEMAP_LINE (new_map)); } - update_header_times (new_map->to_file); + update_header_times (LINEMAP_FILE (new_map)); input_location = new_map->start_location; } @@ -244,7 +240,7 @@ /* Issue a warning message if we have been asked to do so. Ignore unknown pragmas in system headers unless an explicit -Wunknown-pragmas has been given. */ - if (warn_unknown_pragmas > in_system_header) + if (warn_unknown_pragmas > in_system_header_at (input_location)) { const unsigned char *space, *name; const cpp_token *s; @@ -270,7 +266,7 @@ cb_define (cpp_reader *pfile, source_location loc, cpp_hashnode *node) { const struct line_map *map = linemap_lookup (line_table, loc); - (*debug_hooks->define) (SOURCE_LINE (map, loc), + (*debug_hooks->define) (SOURCE_LINE (linemap_check_ordinary (map), loc), (const char *) cpp_macro_definition (pfile, node)); } @@ -280,9 +276,109 @@ cpp_hashnode *node) { const struct line_map *map = linemap_lookup (line_table, loc); - (*debug_hooks->undef) (SOURCE_LINE (map, loc), + (*debug_hooks->undef) (SOURCE_LINE (linemap_check_ordinary (map), loc), (const char *) NODE_NAME (node)); } + +/* Wrapper around cpp_get_token to skip CPP_PADDING tokens + and not consume CPP_EOF. */ +static const cpp_token * +get_token_no_padding (cpp_reader *pfile) +{ + for (;;) + { + const cpp_token *ret = cpp_peek_token (pfile, 0); + if (ret->type == CPP_EOF) + return ret; + ret = cpp_get_token (pfile); + if (ret->type != CPP_PADDING) + return ret; + } +} + +/* Callback for has_attribute. */ +int +c_common_has_attribute (cpp_reader *pfile) +{ + int result = 0; + tree attr_name = NULL_TREE; + const cpp_token *token; + + token = get_token_no_padding (pfile); + if (token->type != CPP_OPEN_PAREN) + { + cpp_error (pfile, CPP_DL_ERROR, + "missing '(' after \"__has_attribute\""); + return 0; + } + token = get_token_no_padding (pfile); + if (token->type == CPP_NAME) + { + attr_name = get_identifier ((const char *) + cpp_token_as_text (pfile, token)); + attr_name = canonicalize_attr_name (attr_name); + if (c_dialect_cxx ()) + { + int idx = 0; + const cpp_token *nxt_token; + do + nxt_token = cpp_peek_token (pfile, idx++); + while (nxt_token->type == CPP_PADDING); + if (nxt_token->type == CPP_SCOPE) + { + get_token_no_padding (pfile); // Eat scope. + nxt_token = get_token_no_padding (pfile); + if (nxt_token->type == CPP_NAME) + { + tree attr_ns = attr_name; + tree attr_id + = get_identifier ((const char *) + cpp_token_as_text (pfile, nxt_token)); + attr_name = build_tree_list (attr_ns, attr_id); + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "attribute identifier required after scope"); + attr_name = NULL_TREE; + } + } + else + { + /* Some standard attributes need special handling. */ + if (is_attribute_p ("noreturn", attr_name)) + result = 200809; + else if (is_attribute_p ("deprecated", attr_name)) + result = 201309; + else if (is_attribute_p ("maybe_unused", attr_name) + || is_attribute_p ("nodiscard", attr_name) + || is_attribute_p ("fallthrough", attr_name)) + result = 201603; + if (result) + attr_name = NULL_TREE; + } + } + if (attr_name) + { + init_attributes (); + const struct attribute_spec *attr = lookup_attribute_spec (attr_name); + if (attr) + result = 1; + } + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "macro \"__has_attribute\" requires an identifier"); + return 0; + } + + if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) + cpp_error (pfile, CPP_DL_ERROR, + "missing ')' after \"__has_attribute\""); + + return result; +} /* Read a token and return its type. Fill *VALUE with its value, if applicable. Fill *CPP_FLAGS with the token's flags, if it is @@ -296,6 +392,7 @@ const cpp_token *tok; enum cpp_ttype type; unsigned char add_flags = 0; + enum overflow_type overflow = OT_NONE; timevar_push (TV_CPP); retry: @@ -314,7 +411,8 @@ case CPP_NUMBER: { - unsigned int flags = cpp_classify_number (parse_in, tok); + const char *suffix = NULL; + unsigned int flags = cpp_classify_number (parse_in, tok, &suffix, *loc); switch (flags & CPP_N_CATEGORY) { @@ -328,16 +426,35 @@ Set PURE_ZERO to pass this information to the C++ parser. */ if (tok->val.str.len == 1 && *tok->val.str.text == '0') add_flags = PURE_ZERO; - *value = interpret_integer (tok, flags); + *value = interpret_integer (tok, flags, &overflow); break; case CPP_N_FLOATING: - *value = interpret_float (tok, flags); + *value = interpret_float (tok, flags, suffix, &overflow); break; default: gcc_unreachable (); } + + if (flags & CPP_N_USERDEF) + { + char *str; + tree literal; + tree suffix_id = get_identifier (suffix); + int len = tok->val.str.len - strlen (suffix); + /* If this is going to be used as a C string to pass to a + raw literal operator, we need to add a trailing NUL. */ + tree num_string = build_string (len + 1, + (const char *) tok->val.str.text); + TREE_TYPE (num_string) = char_array_type_node; + num_string = fix_string_type (num_string); + str = CONST_CAST (char *, TREE_STRING_POINTER (num_string)); + str[len] = '\0'; + literal = build_userdef_literal (suffix_id, *value, overflow, + num_string); + *value = literal; + } } break; @@ -397,7 +514,7 @@ *cpp_spell_token (parse_in, tok, name, true) = 0; - error ("stray %qs in program", name); + error_at (*loc, "stray %qs in program", name); } goto retry; @@ -407,21 +524,56 @@ cppchar_t c = tok->val.str.text[0]; if (c == '"' || c == '\'') - error ("missing terminating %c character", (int) c); + error_at (*loc, "missing terminating %c character", (int) c); else if (ISGRAPH (c)) - error ("stray %qc in program", (int) c); + error_at (*loc, "stray %qc in program", (int) c); else - error ("stray %<\\%o%> in program", (int) c); + error_at (*loc, "stray %<\\%o%> in program", (int) c); } goto retry; + case CPP_CHAR_USERDEF: + case CPP_WCHAR_USERDEF: + case CPP_CHAR16_USERDEF: + case CPP_CHAR32_USERDEF: + case CPP_UTF8CHAR_USERDEF: + { + tree literal; + cpp_token temp_tok = *tok; + const char *suffix = cpp_get_userdef_suffix (tok); + temp_tok.val.str.len -= strlen (suffix); + temp_tok.type = cpp_userdef_char_remove_type (type); + literal = build_userdef_literal (get_identifier (suffix), + lex_charconst (&temp_tok), + OT_NONE, NULL_TREE); + *value = literal; + } + break; + case CPP_CHAR: case CPP_WCHAR: case CPP_CHAR16: case CPP_CHAR32: + case CPP_UTF8CHAR: *value = lex_charconst (tok); break; + case CPP_STRING_USERDEF: + case CPP_WSTRING_USERDEF: + case CPP_STRING16_USERDEF: + case CPP_STRING32_USERDEF: + case CPP_UTF8STRING_USERDEF: + { + tree literal, string; + const char *suffix = cpp_get_userdef_suffix (tok); + string = build_string (tok->val.str.len - strlen (suffix), + (const char *) tok->val.str.text); + literal = build_userdef_literal (get_identifier (suffix), + string, OT_NONE, NULL_TREE); + *value = literal; + } + break; + case CPP_STRING: case CPP_WSTRING: case CPP_STRING16: @@ -437,7 +589,7 @@ break; case CPP_PRAGMA: - *value = build_int_cst (NULL, tok->val.pragma); + *value = build_int_cst (integer_type_node, tok->val.pragma); break; /* These tokens should not be visible outside cpplib. */ @@ -445,9 +597,21 @@ case CPP_MACRO_ARG: gcc_unreachable (); - /* CPP_COMMENT will appear when compiling with -C and should be - ignored. */ - case CPP_COMMENT: + /* CPP_COMMENT will appear when compiling with -C. Ignore, except + when it is a FALLTHROUGH comment, in that case set + PREV_FALLTHROUGH flag on the next non-comment token. */ + case CPP_COMMENT: + if (tok->flags & PREV_FALLTHROUGH) + { + do + { + tok = cpp_get_token_with_location (parse_in, loc); + type = tok->type; + } + while (type == CPP_PADDING || type == CPP_COMMENT); + add_flags |= PREV_FALLTHROUGH; + goto retry_after_at; + } goto retry; default: @@ -474,9 +638,7 @@ there isn't one. */ static enum integer_type_kind -narrowest_unsigned_type (unsigned HOST_WIDE_INT low, - unsigned HOST_WIDE_INT high, - unsigned int flags) +narrowest_unsigned_type (const widest_int &val, unsigned int flags) { int itk; @@ -495,9 +657,7 @@ continue; upper = TYPE_MAX_VALUE (integer_types[itk]); - if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high - || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high - && TREE_INT_CST_LOW (upper) >= low)) + if (wi::geu_p (wi::to_widest (upper), val)) return (enum integer_type_kind) itk; } @@ -506,8 +666,7 @@ /* Ditto, but narrowest signed type. */ static enum integer_type_kind -narrowest_signed_type (unsigned HOST_WIDE_INT low, - unsigned HOST_WIDE_INT high, unsigned int flags) +narrowest_signed_type (const widest_int &val, unsigned int flags) { int itk; @@ -518,7 +677,6 @@ else itk = itk_long_long; - for (; itk < itk_none; itk += 2 /* skip signed types */) { tree upper; @@ -527,9 +685,7 @@ continue; upper = TYPE_MAX_VALUE (integer_types[itk]); - if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) > high - || ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (upper) == high - && TREE_INT_CST_LOW (upper) >= low)) + if (wi::geu_p (wi::to_widest (upper), val)) return (enum integer_type_kind) itk; } @@ -538,28 +694,37 @@ /* Interpret TOKEN, an integer with FLAGS as classified by cpplib. */ static tree -interpret_integer (const cpp_token *token, unsigned int flags) +interpret_integer (const cpp_token *token, unsigned int flags, + enum overflow_type *overflow) { tree value, type; enum integer_type_kind itk; cpp_num integer; - cpp_options *options = cpp_get_options (parse_in); + HOST_WIDE_INT ival[3]; + + *overflow = OT_NONE; integer = cpp_interpret_integer (parse_in, token, flags); - integer = cpp_num_sign_extend (integer, options->precision); + if (integer.overflow) + *overflow = OT_OVERFLOW; + + ival[0] = integer.low; + ival[1] = integer.high; + ival[2] = 0; + widest_int wval = widest_int::from_array (ival, 3); /* The type of a constant with a U suffix is straightforward. */ if (flags & CPP_N_UNSIGNED) - itk = narrowest_unsigned_type (integer.low, integer.high, flags); + itk = narrowest_unsigned_type (wval, flags); else { /* The type of a potentially-signed integer constant varies depending on the base it's in, the standard in use, and the length suffixes. */ enum integer_type_kind itk_u - = narrowest_unsigned_type (integer.low, integer.high, flags); + = narrowest_unsigned_type (wval, flags); enum integer_type_kind itk_s - = narrowest_signed_type (integer.low, integer.high, flags); + = narrowest_signed_type (wval, flags); /* In both C89 and C99, octal and hex constants may be signed or unsigned, whichever fits tighter. We do not warn about this @@ -611,7 +776,7 @@ : "integer constant is too large for %<long%> type"); } - value = build_int_cst_wide (type, integer.low, integer.high); + value = wide_int_to_tree (type, wval); /* Convert imaginary to a complex type. */ if (flags & CPP_N_IMAGINARY) @@ -621,9 +786,10 @@ } /* Interpret TOKEN, a floating point number with FLAGS as classified - by cpplib. */ + by cpplib. For C++11 SUFFIX may contain a user-defined literal suffix. */ static tree -interpret_float (const cpp_token *token, unsigned int flags) +interpret_float (const cpp_token *token, unsigned int flags, + const char *suffix, enum overflow_type *overflow) { tree type; tree const_type; @@ -633,6 +799,8 @@ char *copy; size_t copylen; + *overflow = OT_NONE; + /* Default (no suffix) depends on whether the FLOAT_CONST_DECIMAL64 pragma has been used and is either double or _Decimal64. Types that are not allowed with decimal float default to double. */ @@ -666,7 +834,7 @@ if (flags & CPP_N_WIDTH_MD) { char suffix; - enum machine_mode mode; + machine_mode mode; if ((flags & CPP_N_WIDTH_MD) == CPP_N_MD_W) suffix = 'w'; @@ -681,11 +849,31 @@ return error_mark_node; } else - pedwarn (input_location, OPT_pedantic, "non-standard suffix on floating constant"); + pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant"); type = c_common_type_for_mode (mode, 0); gcc_assert (type); } + else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0) + { + unsigned int n = (flags & CPP_N_WIDTH_FLOATN_NX) >> CPP_FLOATN_SHIFT; + bool extended = (flags & CPP_N_FLOATNX) != 0; + type = NULL_TREE; + for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++) + if (floatn_nx_types[i].n == (int) n + && floatn_nx_types[i].extended == extended) + { + type = FLOATN_NX_TYPE_NODE (i); + break; + } + if (type == NULL_TREE) + { + error ("unsupported non-standard suffix on floating constant"); + return error_mark_node; + } + else + pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant"); + } else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) type = long_double_type_node; else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL @@ -702,7 +890,9 @@ has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF can't handle them. */ copylen = token->val.str.len; - if (flags & CPP_N_DFLOAT) + if (flags & CPP_N_USERDEF) + copylen -= strlen (suffix); + else if (flags & CPP_N_DFLOAT) copylen -= 2; else { @@ -712,11 +902,33 @@ if (flags & CPP_N_IMAGINARY) /* I or J suffix. */ copylen--; + if (flags & CPP_N_FLOATNX) + copylen--; + if (flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) + { + unsigned int n = (flags & CPP_N_WIDTH_FLOATN_NX) >> CPP_FLOATN_SHIFT; + while (n > 0) + { + copylen--; + n /= 10; + } + } } copy = (char *) alloca (copylen + 1); - memcpy (copy, token->val.str.text, copylen); - copy[copylen] = '\0'; + if (cxx_dialect > cxx11) + { + size_t maxlen = 0; + for (size_t i = 0; i < copylen; ++i) + if (token->val.str.text[i] != '\'') + copy[maxlen++] = token->val.str.text[i]; + copy[maxlen] = '\0'; + } + else + { + memcpy (copy, token->val.str.text, copylen); + copy[copylen] = '\0'; + } real_from_string3 (&real, copy, TYPE_MODE (const_type)); if (const_type != type) @@ -734,27 +946,40 @@ if (REAL_VALUE_ISINF (real) || (const_type != type && REAL_VALUE_ISINF (real_trunc))) { - if (!MODE_HAS_INFINITIES (TYPE_MODE (type))) - pedwarn (input_location, 0, "floating constant exceeds range of %qT", type); - else - warning (OPT_Woverflow, "floating constant exceeds range of %qT", type); + *overflow = OT_OVERFLOW; + if (!(flags & CPP_N_USERDEF)) + { + if (!MODE_HAS_INFINITIES (TYPE_MODE (type))) + pedwarn (input_location, 0, + "floating constant exceeds range of %qT", type); + else + warning (OPT_Woverflow, + "floating constant exceeds range of %qT", type); + } } /* We also give a warning if the value underflows. */ - else if (REAL_VALUES_EQUAL (real, dconst0) - || (const_type != type && REAL_VALUES_EQUAL (real_trunc, dconst0))) + else if (real_equal (&real, &dconst0) + || (const_type != type + && real_equal (&real_trunc, &dconst0))) { REAL_VALUE_TYPE realvoidmode; - int overflow = real_from_string (&realvoidmode, copy); - if (overflow < 0 || !REAL_VALUES_EQUAL (realvoidmode, dconst0)) - warning (OPT_Woverflow, "floating constant truncated to zero"); + int oflow = real_from_string (&realvoidmode, copy); + *overflow = (oflow == 0 ? OT_NONE + : (oflow < 0 ? OT_UNDERFLOW : OT_OVERFLOW)); + if (!(flags & CPP_N_USERDEF)) + { + if (oflow < 0 || !real_equal (&realvoidmode, &dconst0)) + warning (OPT_Woverflow, "floating constant truncated to zero"); + } } /* Create a node with determined type and value. */ value = build_real (const_type, real); if (flags & CPP_N_IMAGINARY) { - value = build_complex (NULL_TREE, convert (const_type, - integer_zero_node), value); + value = build_complex (NULL_TREE, + fold_convert (const_type, + integer_zero_node), value); if (type != const_type) { const_type = TREE_TYPE (value); @@ -763,7 +988,7 @@ } if (type != const_type) - value = build1 (EXCESS_PRECISION_EXPR, type, value); + value = build1_loc (token->src_loc, EXCESS_PRECISION_EXPR, type, value); return value; } @@ -885,7 +1110,7 @@ memcpy (copy, token->val.str.text, copylen); copy[copylen] = '\0'; - fixed_from_string (&fixed, copy, TYPE_MODE (type)); + fixed_from_string (&fixed, copy, SCALAR_TYPE_MODE (type)); /* Create a node with determined type and value. */ value = build_fixed (type, fixed); @@ -918,13 +1143,16 @@ tree value; size_t concats = 0; struct obstack str_ob; + struct obstack loc_ob; cpp_string istr; enum cpp_ttype type = tok->type; /* Try to avoid the overhead of creating and destroying an obstack for the common case of just one string. */ cpp_string str = tok->val.str; + location_t init_loc = tok->src_loc; cpp_string *strs = &str; + location_t *locs = NULL; /* objc_at_sign_was_seen is only used when doing Objective-C string concatenation. It is 'true' if we have seen an '@' before the @@ -963,16 +1191,21 @@ else error ("unsupported non-standard concatenation of string literals"); } + /* FALLTHROUGH */ case CPP_STRING: if (!concats) { gcc_obstack_init (&str_ob); + gcc_obstack_init (&loc_ob); obstack_grow (&str_ob, &str, sizeof (cpp_string)); + obstack_grow (&loc_ob, &init_loc, sizeof (location_t)); } concats++; obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string)); + obstack_grow (&loc_ob, &tok->src_loc, sizeof (location_t)); + if (objc_string) objc_at_sign_was_seen = false; goto retry; @@ -985,9 +1218,12 @@ /* We have read one more token than we want. */ _cpp_backup_tokens (parse_in, 1); if (concats) - strs = XOBFINISH (&str_ob, cpp_string *); + { + strs = XOBFINISH (&str_ob, cpp_string *); + locs = XOBFINISH (&loc_ob, location_t *); + } - if (concats && !objc_string && !in_system_header) + if (concats && !objc_string && !in_system_header_at (input_location)) warning (OPT_Wtraditional, "traditional C rejects string constant concatenation"); @@ -997,6 +1233,12 @@ { value = build_string (istr.len, (const char *) istr.text); free (CONST_CAST (unsigned char *, istr.text)); + if (concats) + { + gcc_assert (locs); + gcc_assert (g_string_concat_db); + g_string_concat_db->record_string_concatenation (concats + 1, locs); + } } else { @@ -1048,7 +1290,10 @@ *valp = fix_string_type (value); if (concats) - obstack_free (&str_ob, 0); + { + obstack_free (&str_ob, 0); + obstack_free (&loc_ob, 0); + } return objc_string ? CPP_OBJC_STRING : type; } @@ -1071,6 +1316,8 @@ type = char32_type_node; else if (token->type == CPP_CHAR16) type = char16_type_node; + else if (token->type == CPP_UTF8CHAR) + type = char_type_node; /* In C, a character constant has type 'int'. In C++ 'char', but multi-char charconsts have type 'int'. */ else if (!c_dialect_cxx () || chars_seen > 1) @@ -1081,9 +1328,35 @@ /* Cast to cppchar_signed_t to get correct sign-extension of RESULT before possibly widening to HOST_WIDE_INT for build_int_cst. */ if (unsignedp || (cppchar_signed_t) result >= 0) - value = build_int_cst_wide (type, result, 0); + value = build_int_cst (type, result); else - value = build_int_cst_wide (type, (cppchar_signed_t) result, -1); + value = build_int_cst (type, (cppchar_signed_t) result); return value; } + +/* Helper function for c_parser_peek_conflict_marker + and cp_lexer_peek_conflict_marker. + Given a possible conflict marker token of kind TOK1_KIND + consisting of a pair of characters, get the token kind for the + standalone final character. */ + +enum cpp_ttype +conflict_marker_get_final_tok_kind (enum cpp_ttype tok1_kind) +{ + switch (tok1_kind) + { + default: gcc_unreachable (); + case CPP_LSHIFT: + /* "<<" and '<' */ + return CPP_LESS; + + case CPP_EQ_EQ: + /* "==" and '=' */ + return CPP_EQ; + + case CPP_RSHIFT: + /* ">>" and '>' */ + return CPP_GREATER; + } +}