summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/gcc/gcc/0001-CVE-2021-42574.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/gcc/gcc/0001-CVE-2021-42574.patch')
-rw-r--r--meta/recipes-devtools/gcc/gcc/0001-CVE-2021-42574.patch2906
1 files changed, 2906 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc/0001-CVE-2021-42574.patch b/meta/recipes-devtools/gcc/gcc/0001-CVE-2021-42574.patch
new file mode 100644
index 0000000000..e0f4f7d32f
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc/0001-CVE-2021-42574.patch
@@ -0,0 +1,2906 @@
1From 004bb936d6d5f177af26ad4905595e843d5665a5 Mon Sep 17 00:00:00 2001
2From: Lewis Hyatt <lhyatt@gmail.com>
3Date: Tue, 14 Jul 2020 12:05:56 -0400
4Subject: [PATCH] diagnostics: Support conversion of tabs to spaces [PR49973]
5 [PR86904]
6
7Supports conversion of tabs to spaces when outputting diagnostics. Also
8adds -fdiagnostics-column-unit and -fdiagnostics-column-origin options to
9control how the column number is output, thereby resolving the two PRs.
10
11gcc/c-family/ChangeLog:
12
13 PR other/86904
14 * c-indentation.c (should_warn_for_misleading_indentation): Get
15 global tabstop from the new source.
16 * c-opts.c (c_common_handle_option): Remove handling of -ftabstop, which
17 is now a common option.
18 * c.opt: Likewise.
19
20gcc/ChangeLog:
21
22 PR preprocessor/49973
23 PR other/86904
24 * common.opt: Handle -ftabstop here instead of in c-family
25 options. Add -fdiagnostics-column-unit= and
26 -fdiagnostics-column-origin= options.
27 * opts.c (common_handle_option): Handle the new options.
28 * diagnostic-format-json.cc (json_from_expanded_location): Add
29 diagnostic_context argument. Use it to convert column numbers as per
30 the new options.
31 (json_from_location_range): Likewise.
32 (json_from_fixit_hint): Likewise.
33 (json_end_diagnostic): Pass the new context argument to helper
34 functions above. Add "column-origin" field to the output.
35 (test_unknown_location): Add the new context argument to calls to
36 helper functions.
37 (test_bad_endpoints): Likewise.
38 * diagnostic-show-locus.c
39 (exploc_with_display_col::exploc_with_display_col): Support
40 tabstop parameter.
41 (layout_point::layout_point): Make use of class
42 exploc_with_display_col.
43 (layout_range::layout_range): Likewise.
44 (struct line_bounds): Clarify that the units are now always
45 display columns. Rename members accordingly. Add constructor.
46 (layout::print_source_line): Add support for tab expansion.
47 (make_range): Adapt to class layout_range changes.
48 (layout::maybe_add_location_range): Likewise.
49 (layout::layout): Adapt to class exploc_with_display_col changes.
50 (layout::calculate_x_offset_display): Support tabstop parameter.
51 (layout::print_annotation_line): Adapt to struct line_bounds changes.
52 (layout::print_line): Likewise.
53 (line_label::line_label): Add diagnostic_context argument.
54 (get_affected_range): Likewise.
55 (get_printed_columns): Likewise.
56 (layout::print_any_labels): Adapt to struct line_label changes.
57 (class correction): Add m_tabstop member.
58 (correction::correction): Add tabstop argument.
59 (correction::compute_display_cols): Use m_tabstop.
60 (class line_corrections): Add m_context member.
61 (line_corrections::line_corrections): Add diagnostic_context argument.
62 (line_corrections::add_hint): Use m_context to handle tabstops.
63 (layout::print_trailing_fixits): Adapt to class line_corrections
64 changes.
65 (test_layout_x_offset_display_utf8): Support tabstop parameter.
66 (test_layout_x_offset_display_tab): New selftest.
67 (test_one_liner_colorized_utf8): Likewise.
68 (test_tab_expansion): Likewise.
69 (test_diagnostic_show_locus_one_liner_utf8): Call the new tests.
70 (diagnostic_show_locus_c_tests): Likewise.
71 (test_overlapped_fixit_printing): Adapt to helper class and
72 function changes.
73 (test_overlapped_fixit_printing_utf8): Likewise.
74 (test_overlapped_fixit_printing_2): Likewise.
75 * diagnostic.h (enum diagnostics_column_unit): New enum.
76 (struct diagnostic_context): Add members for the new options.
77 (diagnostic_converted_column): Declare.
78 (json_from_expanded_location): Add new context argument.
79 * diagnostic.c (diagnostic_initialize): Initialize new members.
80 (diagnostic_converted_column): New function.
81 (maybe_line_and_column): Be willing to output a column of 0.
82 (diagnostic_get_location_text): Convert column number as per the new
83 options.
84 (diagnostic_report_current_module): Likewise.
85 (assert_location_text): Add origin and column_unit arguments for
86 testing the new functionality.
87 (test_diagnostic_get_location_text): Test the new functionality.
88 * doc/invoke.texi: Document the new options and behavior.
89 * input.h (location_compute_display_column): Add tabstop argument.
90 * input.c (location_compute_display_column): Likewise.
91 (test_cpp_utf8): Add selftests for tab expansion.
92 * tree-diagnostic-path.cc (default_tree_make_json_for_path): Pass the
93 new context argument to json_from_expanded_location().
94
95libcpp/ChangeLog:
96
97 PR preprocessor/49973
98 PR other/86904
99 * include/cpplib.h (struct cpp_options): Removed support for -ftabstop,
100 which is now handled by diagnostic_context.
101 (class cpp_display_width_computation): New class.
102 (cpp_byte_column_to_display_column): Add optional tabstop argument.
103 (cpp_display_width): Likewise.
104 (cpp_display_column_to_byte_column): Likewise.
105 * charset.c
106 (cpp_display_width_computation::cpp_display_width_computation): New
107 function.
108 (cpp_display_width_computation::advance_display_cols): Likewise.
109 (compute_next_display_width): Removed and implemented this
110 functionality in a new function...
111 (cpp_display_width_computation::process_next_codepoint): ...here.
112 (cpp_byte_column_to_display_column): Added tabstop argument.
113 Reimplemented in terms of class cpp_display_width_computation.
114 (cpp_display_column_to_byte_column): Likewise.
115 * init.c (cpp_create_reader): Remove handling of -ftabstop, which is now
116 handled by diagnostic_context.
117
118gcc/testsuite/ChangeLog:
119
120 PR preprocessor/49973
121 PR other/86904
122 * c-c++-common/Wmisleading-indentation-3.c: Adjust expected output
123 for new defaults.
124 * c-c++-common/Wmisleading-indentation.c: Likewise.
125 * c-c++-common/diagnostic-format-json-1.c: Likewise.
126 * c-c++-common/diagnostic-format-json-2.c: Likewise.
127 * c-c++-common/diagnostic-format-json-3.c: Likewise.
128 * c-c++-common/diagnostic-format-json-4.c: Likewise.
129 * c-c++-common/diagnostic-format-json-5.c: Likewise.
130 * c-c++-common/missing-close-symbol.c: Likewise.
131 * g++.dg/diagnostic/bad-binary-ops.C: Likewise.
132 * g++.dg/parse/error4.C: Likewise.
133 * g++.old-deja/g++.brendan/crash11.C: Likewise.
134 * g++.old-deja/g++.pt/overload2.C: Likewise.
135 * g++.old-deja/g++.robertl/eb109.C: Likewise.
136 * gcc.dg/analyzer/malloc-paths-9.c: Likewise.
137 * gcc.dg/bad-binary-ops.c: Likewise.
138 * gcc.dg/format/branch-1.c: Likewise.
139 * gcc.dg/format/pr79210.c: Likewise.
140 * gcc.dg/plugin/diagnostic-test-expressions-1.c: Likewise.
141 * gcc.dg/plugin/diagnostic-test-string-literals-1.c: Likewise.
142 * gcc.dg/redecl-4.c: Likewise.
143 * gfortran.dg/diagnostic-format-json-1.F90: Likewise.
144 * gfortran.dg/diagnostic-format-json-2.F90: Likewise.
145 * gfortran.dg/diagnostic-format-json-3.F90: Likewise.
146 * go.dg/arrayclear.go: Add a comment explaining why adding a
147 comment was necessary to work around a dejagnu bug.
148 * c-c++-common/diagnostic-units-1.c: New test.
149 * c-c++-common/diagnostic-units-2.c: New test.
150 * c-c++-common/diagnostic-units-3.c: New test.
151 * c-c++-common/diagnostic-units-4.c: New test.
152 * c-c++-common/diagnostic-units-5.c: New test.
153 * c-c++-common/diagnostic-units-6.c: New test.
154 * c-c++-common/diagnostic-units-7.c: New test.
155 * c-c++-common/diagnostic-units-8.c: New test.
156
157CVE: CVE-2021-42574
158Upstream-Status: Backport [https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=004bb936d6d5f177af26ad4905595e843d5665a5]
159Signed-off-by: Pgowda <pgowda.cve@gmail.com>
160---
161 gcc/c-family/c-indentation.c | 5 +-
162 gcc/c-family/c-opts.c | 6 -
163 gcc/c-family/c.opt | 4 -
164 gcc/common.opt | 21 +
165 gcc/diagnostic-format-json.cc | 55 +-
166 gcc/diagnostic-show-locus.c | 504 +++++++++++++-----
167 gcc/diagnostic.c | 113 +++-
168 gcc/diagnostic.h | 28 +-
169 gcc/doc/invoke.texi | 68 ++-
170 gcc/input.c | 72 ++-
171 gcc/input.h | 4 +-
172 gcc/opts.c | 14 +
173 .../c-c++-common/Wmisleading-indentation-3.c | 12 +-
174 .../c-c++-common/Wmisleading-indentation.c | 6 +-
175 .../c-c++-common/diagnostic-format-json-1.c | 5 +
176 .../c-c++-common/diagnostic-format-json-2.c | 5 +
177 .../c-c++-common/diagnostic-format-json-3.c | 5 +
178 .../c-c++-common/diagnostic-format-json-4.c | 9 +
179 .../c-c++-common/diagnostic-format-json-5.c | 9 +
180 .../c-c++-common/diagnostic-units-1.c | 28 +
181 .../c-c++-common/diagnostic-units-2.c | 28 +
182 .../c-c++-common/diagnostic-units-3.c | 28 +
183 .../c-c++-common/diagnostic-units-4.c | 28 +
184 .../c-c++-common/diagnostic-units-5.c | 28 +
185 .../c-c++-common/diagnostic-units-6.c | 28 +
186 .../c-c++-common/diagnostic-units-7.c | 28 +
187 .../c-c++-common/diagnostic-units-8.c | 28 +
188 .../c-c++-common/missing-close-symbol.c | 6 +-
189 .../g++.dg/diagnostic/bad-binary-ops.C | 8 +-
190 gcc/testsuite/g++.dg/parse/error4.C | 2 +-
191 .../g++.old-deja/g++.brendan/crash11.C | 4 +-
192 gcc/testsuite/g++.old-deja/g++.pt/overload2.C | 2 +-
193 .../g++.old-deja/g++.robertl/eb109.C | 4 +-
194 .../gcc.dg/analyzer/malloc-paths-9.c | 2 +-
195 gcc/testsuite/gcc.dg/bad-binary-ops.c | 8 +-
196 gcc/testsuite/gcc.dg/format/branch-1.c | 2 +-
197 gcc/testsuite/gcc.dg/format/pr79210.c | 2 +-
198 .../plugin/diagnostic-test-expressions-1.c | 16 +-
199 .../diagnostic-test-string-literals-1.c | 4 +-
200 gcc/testsuite/gcc.dg/redecl-4.c | 2 +-
201 .../gfortran.dg/diagnostic-format-json-1.F90 | 5 +
202 .../gfortran.dg/diagnostic-format-json-2.F90 | 5 +
203 .../gfortran.dg/diagnostic-format-json-3.F90 | 5 +
204 gcc/testsuite/go.dg/arrayclear.go | 3 +
205 gcc/tree-diagnostic-path.cc | 5 +-
206 libcpp/charset.c | 98 ++--
207 libcpp/include/cpplib.h | 40 +-
208 libcpp/init.c | 1 -
209 48 files changed, 1106 insertions(+), 287 deletions(-)
210 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-1.c
211 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-2.c
212 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-3.c
213 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-4.c
214 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-5.c
215 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-6.c
216 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-7.c
217 create mode 100644 gcc/testsuite/c-c++-common/diagnostic-units-8.c
218
219diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
220--- a/gcc/c-family/c-indentation.c 2020-07-22 23:35:17.296384022 -0700
221+++ b/gcc/c-family/c-indentation.c 2021-12-25 01:20:53.475636694 -0800
222@@ -24,8 +24,7 @@ along with GCC; see the file COPYING3.
223 #include "c-common.h"
224 #include "c-indentation.h"
225 #include "selftest.h"
226-
227-extern cpp_options *cpp_opts;
228+#include "diagnostic.h"
229
230 /* Round up VIS_COLUMN to nearest tab stop. */
231
232@@ -294,7 +293,7 @@ should_warn_for_misleading_indentation (
233 expanded_location next_stmt_exploc = expand_location (next_stmt_loc);
234 expanded_location guard_exploc = expand_location (guard_loc);
235
236- const unsigned int tab_width = cpp_opts->tabstop;
237+ const unsigned int tab_width = global_dc->tabstop;
238
239 /* They must be in the same file. */
240 if (next_stmt_exploc.file != body_exploc.file)
241diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
242--- a/gcc/c-family/c.opt 2021-12-24 20:23:42.816809230 -0800
243+++ b/gcc/c-family/c.opt 2021-12-25 01:20:53.475636694 -0800
244@@ -1876,10 +1876,6 @@ Enum(strong_eval_order) String(some) Val
245 EnumValue
246 Enum(strong_eval_order) String(all) Value(2)
247
248-ftabstop=
249-C ObjC C++ ObjC++ Joined RejectNegative UInteger
250--ftabstop=<number> Distance between tab stops for column reporting.
251-
252 ftemplate-backtrace-limit=
253 C++ ObjC++ Joined RejectNegative UInteger Var(template_backtrace_limit) Init(10)
254 Set the maximum number of template instantiation notes for a single warning or error.
255diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
256--- a/gcc/c-family/c-opts.c 2021-12-24 20:23:44.824774786 -0800
257+++ b/gcc/c-family/c-opts.c 2021-12-25 01:20:53.475636694 -0800
258@@ -504,12 +504,6 @@ c_common_handle_option (size_t scode, co
259 cpp_opts->track_macro_expansion = 2;
260 break;
261
262- case OPT_ftabstop_:
263- /* It is documented that we silently ignore silly values. */
264- if (value >= 1 && value <= 100)
265- cpp_opts->tabstop = value;
266- break;
267-
268 case OPT_fexec_charset_:
269 cpp_opts->narrow_charset = arg;
270 break;
271diff --git a/gcc/common.opt b/gcc/common.opt
272--- a/gcc/common.opt 2021-12-24 20:23:42.480814993 -0800
273+++ b/gcc/common.opt 2021-12-25 01:20:53.475636694 -0800
274@@ -1325,6 +1325,14 @@ Enum(diagnostic_url_rule) String(always)
275 EnumValue
276 Enum(diagnostic_url_rule) String(auto) Value(DIAGNOSTICS_URL_AUTO)
277
278+fdiagnostics-column-unit=
279+Common Joined RejectNegative Enum(diagnostics_column_unit)
280+-fdiagnostics-column-unit=[display|byte] Select whether column numbers are output as display columns (default) or raw bytes.
281+
282+fdiagnostics-column-origin=
283+Common Joined RejectNegative UInteger
284+-fdiagnostics-column-origin=<number> Set the number of the first column. The default is 1-based as per GNU style, but some utilities may expect 0-based, for example.
285+
286 fdiagnostics-format=
287 Common Joined RejectNegative Enum(diagnostics_output_format)
288 -fdiagnostics-format=[text|json] Select output format.
289@@ -1334,6 +1342,15 @@ SourceInclude
290 diagnostic.h
291
292 Enum
293+Name(diagnostics_column_unit) Type(int)
294+
295+EnumValue
296+Enum(diagnostics_column_unit) String(display) Value(DIAGNOSTICS_COLUMN_UNIT_DISPLAY)
297+
298+EnumValue
299+Enum(diagnostics_column_unit) String(byte) Value(DIAGNOSTICS_COLUMN_UNIT_BYTE)
300+
301+Enum
302 Name(diagnostics_output_format) Type(int)
303
304 EnumValue
305@@ -1362,6 +1379,10 @@ fdiagnostics-path-format=
306 Common Joined RejectNegative Var(flag_diagnostics_path_format) Enum(diagnostic_path_format) Init(DPF_INLINE_EVENTS)
307 Specify how to print any control-flow path associated with a diagnostic.
308
309+ftabstop=
310+Common Joined RejectNegative UInteger
311+-ftabstop=<number> Distance between tab stops for column reporting.
312+
313 Enum
314 Name(diagnostic_path_format) Type(int)
315
316diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
317--- a/gcc/diagnostic.c 2020-07-22 23:35:17.556386887 -0700
318+++ b/gcc/diagnostic.c 2021-12-25 01:23:41.300841207 -0800
319@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.
320 #include "selftest.h"
321 #include "selftest-diagnostic.h"
322 #include "opts.h"
323+#include "cpplib.h"
324
325 #ifdef HAVE_TERMIOS_H
326 # include <termios.h>
327@@ -219,6 +220,9 @@ diagnostic_initialize (diagnostic_contex
328 context->min_margin_width = 0;
329 context->show_ruler_p = false;
330 context->parseable_fixits_p = false;
331+ context->column_unit = DIAGNOSTICS_COLUMN_UNIT_DISPLAY;
332+ context->column_origin = 1;
333+ context->tabstop = 8;
334 context->edit_context_ptr = NULL;
335 context->diagnostic_group_nesting_depth = 0;
336 context->diagnostic_group_emission_count = 0;
337@@ -353,8 +357,51 @@ diagnostic_get_color_for_kind (diagnosti
338 return diagnostic_kind_color[kind];
339 }
340
341+/* Given an expanded_location, convert the column (which is in 1-based bytes)
342+ to the requested units, without converting the origin.
343+ Return -1 if the column is invalid (<= 0). */
344+
345+static int
346+convert_column_unit (enum diagnostics_column_unit column_unit,
347+ int tabstop,
348+ expanded_location s)
349+{
350+ if (s.column <= 0)
351+ return -1;
352+
353+ switch (column_unit)
354+ {
355+ default:
356+ gcc_unreachable ();
357+
358+ case DIAGNOSTICS_COLUMN_UNIT_DISPLAY:
359+ {
360+ cpp_char_column_policy policy (tabstop, cpp_wcwidth);
361+ return location_compute_display_column (s, policy);
362+ }
363+
364+ case DIAGNOSTICS_COLUMN_UNIT_BYTE:
365+ return s.column;
366+ }
367+}
368+
369+/* Given an expanded_location, convert the column (which is in 1-based bytes)
370+ to the requested units and origin. Return -1 if the column is
371+ invalid (<= 0). */
372+int
373+diagnostic_converted_column (diagnostic_context *context, expanded_location s)
374+{
375+ int one_based_col
376+ = convert_column_unit (context->column_unit, context->tabstop, s);
377+ if (one_based_col <= 0)
378+ return -1;
379+ return one_based_col + (context->column_origin - 1);
380+}
381+
382 /* Return a formatted line and column ':%line:%column'. Elided if
383- zero. The result is a statically allocated buffer. */
384+ line == 0 or col < 0. (A column of 0 may be valid due to the
385+ -fdiagnostics-column-origin option.)
386+ The result is a statically allocated buffer. */
387
388 static const char *
389 maybe_line_and_column (int line, int col)
390@@ -363,8 +410,9 @@ maybe_line_and_column (int line, int col
391
392 if (line)
393 {
394- size_t l = snprintf (result, sizeof (result),
395- col ? ":%d:%d" : ":%d", line, col);
396+ size_t l
397+ = snprintf (result, sizeof (result),
398+ col >= 0 ? ":%d:%d" : ":%d", line, col);
399 gcc_checking_assert (l < sizeof (result));
400 }
401 else
402@@ -383,8 +431,14 @@ diagnostic_get_location_text (diagnostic
403 const char *locus_cs = colorize_start (pp_show_color (pp), "locus");
404 const char *locus_ce = colorize_stop (pp_show_color (pp));
405 const char *file = s.file ? s.file : progname;
406- int line = strcmp (file, N_("<built-in>")) ? s.line : 0;
407- int col = context->show_column ? s.column : 0;
408+ int line = 0;
409+ int col = -1;
410+ if (strcmp (file, N_("<built-in>")))
411+ {
412+ line = s.line;
413+ if (context->show_column)
414+ col = diagnostic_converted_column (context, s);
415+ }
416
417 const char *line_col = maybe_line_and_column (line, col);
418 return build_message_string ("%s%s%s:%s", locus_cs, file,
419@@ -650,14 +704,20 @@ diagnostic_report_current_module (diagno
420 if (! MAIN_FILE_P (map))
421 {
422 bool first = true;
423+ expanded_location s = {};
424 do
425 {
426 where = linemap_included_from (map);
427 map = linemap_included_from_linemap (line_table, map);
428- const char *line_col
429- = maybe_line_and_column (SOURCE_LINE (map, where),
430- first && context->show_column
431- ? SOURCE_COLUMN (map, where) : 0);
432+ s.file = LINEMAP_FILE (map);
433+ s.line = SOURCE_LINE (map, where);
434+ int col = -1;
435+ if (first && context->show_column)
436+ {
437+ s.column = SOURCE_COLUMN (map, where);
438+ col = diagnostic_converted_column (context, s);
439+ }
440+ const char *line_col = maybe_line_and_column (s.line, col);
441 static const char *const msgs[] =
442 {
443 N_("In file included from"),
444@@ -666,7 +726,7 @@ diagnostic_report_current_module (diagno
445 unsigned index = !first;
446 pp_verbatim (context->printer, "%s%s %r%s%s%R",
447 first ? "" : ",\n", _(msgs[index]),
448- "locus", LINEMAP_FILE (map), line_col);
449+ "locus", s.file, line_col);
450 first = false;
451 }
452 while (! MAIN_FILE_P (map));
453@@ -2042,10 +2102,15 @@ test_print_parseable_fixits_replace ()
454 static void
455 assert_location_text (const char *expected_loc_text,
456 const char *filename, int line, int column,
457- bool show_column)
458+ bool show_column,
459+ int origin = 1,
460+ enum diagnostics_column_unit column_unit
461+ = DIAGNOSTICS_COLUMN_UNIT_BYTE)
462 {
463 test_diagnostic_context dc;
464 dc.show_column = show_column;
465+ dc.column_unit = column_unit;
466+ dc.column_origin = origin;
467
468 expanded_location xloc;
469 xloc.file = filename;
470@@ -2069,7 +2134,10 @@ test_diagnostic_get_location_text ()
471 assert_location_text ("PROGNAME:", NULL, 0, 0, true);
472 assert_location_text ("<built-in>:", "<built-in>", 42, 10, true);
473 assert_location_text ("foo.c:42:10:", "foo.c", 42, 10, true);
474- assert_location_text ("foo.c:42:", "foo.c", 42, 0, true);
475+ assert_location_text ("foo.c:42:9:", "foo.c", 42, 10, true, 0);
476+ assert_location_text ("foo.c:42:1010:", "foo.c", 42, 10, true, 1001);
477+ for (int origin = 0; origin != 2; ++origin)
478+ assert_location_text ("foo.c:42:", "foo.c", 42, 0, true, origin);
479 assert_location_text ("foo.c:", "foo.c", 0, 10, true);
480 assert_location_text ("foo.c:42:", "foo.c", 42, 10, false);
481 assert_location_text ("foo.c:", "foo.c", 0, 10, false);
482@@ -2077,6 +2145,41 @@ test_diagnostic_get_location_text ()
483 maybe_line_and_column (INT_MAX, INT_MAX);
484 maybe_line_and_column (INT_MIN, INT_MIN);
485
486+ {
487+ /* In order to test display columns vs byte columns, we need to create a
488+ file for location_get_source_line() to read. */
489+
490+ const char *const content = "smile \xf0\x9f\x98\x82\n";
491+ const int line_bytes = strlen (content) - 1;
492+ const int def_tabstop = 8;
493+ const int display_width = cpp_display_width (content, line_bytes,
494+ def_tabstop);
495+ ASSERT_EQ (line_bytes - 2, display_width);
496+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
497+ const char *const fname = tmp.get_filename ();
498+ const int buf_len = strlen (fname) + 16;
499+ char *const expected = XNEWVEC (char, buf_len);
500+
501+ snprintf (expected, buf_len, "%s:1:%d:", fname, line_bytes);
502+ assert_location_text (expected, fname, 1, line_bytes, true,
503+ 1, DIAGNOSTICS_COLUMN_UNIT_BYTE);
504+
505+ snprintf (expected, buf_len, "%s:1:%d:", fname, line_bytes - 1);
506+ assert_location_text (expected, fname, 1, line_bytes, true,
507+ 0, DIAGNOSTICS_COLUMN_UNIT_BYTE);
508+
509+ snprintf (expected, buf_len, "%s:1:%d:", fname, display_width);
510+ assert_location_text (expected, fname, 1, line_bytes, true,
511+ 1, DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
512+
513+ snprintf (expected, buf_len, "%s:1:%d:", fname, display_width - 1);
514+ assert_location_text (expected, fname, 1, line_bytes, true,
515+ 0, DIAGNOSTICS_COLUMN_UNIT_DISPLAY);
516+
517+ XDELETEVEC (expected);
518+ }
519+
520+
521 progname = old_progname;
522 }
523
524diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
525--- a/gcc/diagnostic-format-json.cc 2020-07-22 23:35:17.556386887 -0700
526+++ b/gcc/diagnostic-format-json.cc 2021-12-25 01:20:53.475636694 -0800
527@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.
528 #include "system.h"
529 #include "coretypes.h"
530 #include "diagnostic.h"
531+#include "selftest-diagnostic.h"
532 #include "diagnostic-metadata.h"
533 #include "json.h"
534 #include "selftest.h"
535@@ -43,21 +44,43 @@ static json::array *cur_children_array;
536 /* Generate a JSON object for LOC. */
537
538 json::value *
539-json_from_expanded_location (location_t loc)
540+json_from_expanded_location (diagnostic_context *context, location_t loc)
541 {
542 expanded_location exploc = expand_location (loc);
543 json::object *result = new json::object ();
544 if (exploc.file)
545 result->set ("file", new json::string (exploc.file));
546 result->set ("line", new json::integer_number (exploc.line));
547- result->set ("column", new json::integer_number (exploc.column));
548+
549+ const enum diagnostics_column_unit orig_unit = context->column_unit;
550+ struct
551+ {
552+ const char *name;
553+ enum diagnostics_column_unit unit;
554+ } column_fields[] = {
555+ {"display-column", DIAGNOSTICS_COLUMN_UNIT_DISPLAY},
556+ {"byte-column", DIAGNOSTICS_COLUMN_UNIT_BYTE}
557+ };
558+ int the_column = INT_MIN;
559+ for (int i = 0; i != sizeof column_fields / sizeof (*column_fields); ++i)
560+ {
561+ context->column_unit = column_fields[i].unit;
562+ const int col = diagnostic_converted_column (context, exploc);
563+ result->set (column_fields[i].name, new json::integer_number (col));
564+ if (column_fields[i].unit == orig_unit)
565+ the_column = col;
566+ }
567+ gcc_assert (the_column != INT_MIN);
568+ result->set ("column", new json::integer_number (the_column));
569+ context->column_unit = orig_unit;
570 return result;
571 }
572
573 /* Generate a JSON object for LOC_RANGE. */
574
575 static json::object *
576-json_from_location_range (const location_range *loc_range, unsigned range_idx)
577+json_from_location_range (diagnostic_context *context,
578+ const location_range *loc_range, unsigned range_idx)
579 {
580 location_t caret_loc = get_pure_location (loc_range->m_loc);
581
582@@ -68,13 +91,13 @@ json_from_location_range (const location
583 location_t finish_loc = get_finish (loc_range->m_loc);
584
585 json::object *result = new json::object ();
586- result->set ("caret", json_from_expanded_location (caret_loc));
587+ result->set ("caret", json_from_expanded_location (context, caret_loc));
588 if (start_loc != caret_loc
589 && start_loc != UNKNOWN_LOCATION)
590- result->set ("start", json_from_expanded_location (start_loc));
591+ result->set ("start", json_from_expanded_location (context, start_loc));
592 if (finish_loc != caret_loc
593 && finish_loc != UNKNOWN_LOCATION)
594- result->set ("finish", json_from_expanded_location (finish_loc));
595+ result->set ("finish", json_from_expanded_location (context, finish_loc));
596
597 if (loc_range->m_label)
598 {
599@@ -91,14 +114,14 @@ json_from_location_range (const location
600 /* Generate a JSON object for HINT. */
601
602 static json::object *
603-json_from_fixit_hint (const fixit_hint *hint)
604+json_from_fixit_hint (diagnostic_context *context, const fixit_hint *hint)
605 {
606 json::object *fixit_obj = new json::object ();
607
608 location_t start_loc = hint->get_start_loc ();
609- fixit_obj->set ("start", json_from_expanded_location (start_loc));
610+ fixit_obj->set ("start", json_from_expanded_location (context, start_loc));
611 location_t next_loc = hint->get_next_loc ();
612- fixit_obj->set ("next", json_from_expanded_location (next_loc));
613+ fixit_obj->set ("next", json_from_expanded_location (context, next_loc));
614 fixit_obj->set ("string", new json::string (hint->get_string ()));
615
616 return fixit_obj;
617@@ -190,11 +213,13 @@ json_end_diagnostic (diagnostic_context
618 else
619 {
620 /* Otherwise, make diag_obj be the top-level object within the group;
621- add a "children" array. */
622+ add a "children" array and record the column origin. */
623 toplevel_array->append (diag_obj);
624 cur_group = diag_obj;
625 cur_children_array = new json::array ();
626 diag_obj->set ("children", cur_children_array);
627+ diag_obj->set ("column-origin",
628+ new json::integer_number (context->column_origin));
629 }
630
631 const rich_location *richloc = diagnostic->richloc;
632@@ -205,7 +230,7 @@ json_end_diagnostic (diagnostic_context
633 for (unsigned int i = 0; i < richloc->get_num_locations (); i++)
634 {
635 const location_range *loc_range = richloc->get_range (i);
636- json::object *loc_obj = json_from_location_range (loc_range, i);
637+ json::object *loc_obj = json_from_location_range (context, loc_range, i);
638 if (loc_obj)
639 loc_array->append (loc_obj);
640 }
641@@ -217,7 +242,7 @@ json_end_diagnostic (diagnostic_context
642 for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
643 {
644 const fixit_hint *hint = richloc->get_fixit_hint (i);
645- json::object *fixit_obj = json_from_fixit_hint (hint);
646+ json::object *fixit_obj = json_from_fixit_hint (context, hint);
647 fixit_array->append (fixit_obj);
648 }
649 }
650@@ -320,7 +345,8 @@ namespace selftest {
651 static void
652 test_unknown_location ()
653 {
654- delete json_from_expanded_location (UNKNOWN_LOCATION);
655+ test_diagnostic_context dc;
656+ delete json_from_expanded_location (&dc, UNKNOWN_LOCATION);
657 }
658
659 /* Verify that we gracefully handle attempts to serialize bad
660@@ -338,7 +364,8 @@ test_bad_endpoints ()
661 loc_range.m_range_display_kind = SHOW_RANGE_WITH_CARET;
662 loc_range.m_label = NULL;
663
664- json::object *obj = json_from_location_range (&loc_range, 0);
665+ test_diagnostic_context dc;
666+ json::object *obj = json_from_location_range (&dc, &loc_range, 0);
667 /* We should have a "caret" value, but no "start" or "finish" values. */
668 ASSERT_TRUE (obj != NULL);
669 ASSERT_TRUE (obj->get ("caret") != NULL);
670diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
671--- a/gcc/diagnostic.h 2020-07-22 23:35:17.556386887 -0700
672+++ b/gcc/diagnostic.h 2021-12-25 01:20:53.479636627 -0800
673@@ -24,6 +24,20 @@ along with GCC; see the file COPYING3.
674 #include "pretty-print.h"
675 #include "diagnostic-core.h"
676
677+/* An enum for controlling what units to use for the column number
678+ when diagnostics are output, used by the -fdiagnostics-column-unit option.
679+ Tabs will be expanded or not according to the value of -ftabstop. The origin
680+ (default 1) is controlled by -fdiagnostics-column-origin. */
681+
682+enum diagnostics_column_unit
683+{
684+ /* The default from GCC 11 onwards: display columns. */
685+ DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
686+
687+ /* The behavior in GCC 10 and earlier: simple bytes. */
688+ DIAGNOSTICS_COLUMN_UNIT_BYTE
689+};
690+
691 /* Enum for overriding the standard output format. */
692
693 enum diagnostics_output_format
694@@ -280,6 +294,15 @@ struct diagnostic_context
695 rest of the diagnostic. */
696 bool parseable_fixits_p;
697
698+ /* What units to use when outputting the column number. */
699+ enum diagnostics_column_unit column_unit;
700+
701+ /* The origin for the column number (1-based or 0-based typically). */
702+ int column_origin;
703+
704+ /* The size of the tabstop for tab expansion. */
705+ int tabstop;
706+
707 /* If non-NULL, an edit_context to which fix-it hints should be
708 applied, for generating patches. */
709 edit_context *edit_context_ptr;
710@@ -458,6 +481,8 @@ diagnostic_same_line (const diagnostic_c
711 }
712
713 extern const char *diagnostic_get_color_for_kind (diagnostic_t kind);
714+extern int diagnostic_converted_column (diagnostic_context *context,
715+ expanded_location s);
716
717 /* Pure text formatting support functions. */
718 extern char *file_name_as_prefix (diagnostic_context *, const char *);
719@@ -470,6 +495,7 @@ extern void diagnostic_output_format_ini
720 /* Compute the number of digits in the decimal representation of an integer. */
721 extern int num_digits (int);
722
723-extern json::value *json_from_expanded_location (location_t loc);
724+extern json::value *json_from_expanded_location (diagnostic_context *context,
725+ location_t loc);
726
727 #endif /* ! GCC_DIAGNOSTIC_H */
728diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
729--- a/gcc/diagnostic-show-locus.c 2020-07-22 23:35:17.556386887 -0700
730+++ b/gcc/diagnostic-show-locus.c 2021-12-25 01:20:53.479636627 -0800
731@@ -175,9 +175,10 @@ enum column_unit {
732 class exploc_with_display_col : public expanded_location
733 {
734 public:
735- exploc_with_display_col (const expanded_location &exploc)
736+ exploc_with_display_col (const expanded_location &exploc, int tabstop)
737 : expanded_location (exploc),
738- m_display_col (location_compute_display_column (exploc)) {}
739+ m_display_col (location_compute_display_column (exploc, tabstop))
740+ {}
741
742 int m_display_col;
743 };
744@@ -189,11 +190,11 @@ class exploc_with_display_col : public e
745 class layout_point
746 {
747 public:
748- layout_point (const expanded_location &exploc)
749+ layout_point (const exploc_with_display_col &exploc)
750 : m_line (exploc.line)
751 {
752 m_columns[CU_BYTES] = exploc.column;
753- m_columns[CU_DISPLAY_COLS] = location_compute_display_column (exploc);
754+ m_columns[CU_DISPLAY_COLS] = exploc.m_display_col;
755 }
756
757 linenum_type m_line;
758@@ -205,10 +206,10 @@ class layout_point
759 class layout_range
760 {
761 public:
762- layout_range (const expanded_location *start_exploc,
763- const expanded_location *finish_exploc,
764+ layout_range (const exploc_with_display_col &start_exploc,
765+ const exploc_with_display_col &finish_exploc,
766 enum range_display_kind range_display_kind,
767- const expanded_location *caret_exploc,
768+ const exploc_with_display_col &caret_exploc,
769 unsigned original_idx,
770 const range_label *label);
771
772@@ -226,22 +227,18 @@ class layout_range
773
774 /* A struct for use by layout::print_source_line for telling
775 layout::print_annotation_line the extents of the source line that
776- it printed, so that underlines can be clipped appropriately. */
777+ it printed, so that underlines can be clipped appropriately. Units
778+ are 1-based display columns. */
779
780 struct line_bounds
781 {
782- int m_first_non_ws;
783- int m_last_non_ws;
784+ int m_first_non_ws_disp_col;
785+ int m_last_non_ws_disp_col;
786
787- void convert_to_display_cols (char_span line)
788+ line_bounds ()
789 {
790- m_first_non_ws = cpp_byte_column_to_display_column (line.get_buffer (),
791- line.length (),
792- m_first_non_ws);
793-
794- m_last_non_ws = cpp_byte_column_to_display_column (line.get_buffer (),
795- line.length (),
796- m_last_non_ws);
797+ m_first_non_ws_disp_col = INT_MAX;
798+ m_last_non_ws_disp_col = 0;
799 }
800 };
801
802@@ -351,8 +348,8 @@ class layout
803 private:
804 bool will_show_line_p (linenum_type row) const;
805 void print_leading_fixits (linenum_type row);
806- void print_source_line (linenum_type row, const char *line, int line_bytes,
807- line_bounds *lbounds_out);
808+ line_bounds print_source_line (linenum_type row, const char *line,
809+ int line_bytes);
810 bool should_print_annotation_line_p (linenum_type row) const;
811 void start_annotation_line (char margin_char = ' ') const;
812 void print_annotation_line (linenum_type row, const line_bounds lbounds);
813@@ -513,16 +510,16 @@ colorizer::get_color_by_name (const char
814 Initialize various layout_point fields from expanded_location
815 equivalents; we've already filtered on file. */
816
817-layout_range::layout_range (const expanded_location *start_exploc,
818- const expanded_location *finish_exploc,
819+layout_range::layout_range (const exploc_with_display_col &start_exploc,
820+ const exploc_with_display_col &finish_exploc,
821 enum range_display_kind range_display_kind,
822- const expanded_location *caret_exploc,
823+ const exploc_with_display_col &caret_exploc,
824 unsigned original_idx,
825 const range_label *label)
826-: m_start (*start_exploc),
827- m_finish (*finish_exploc),
828+: m_start (start_exploc),
829+ m_finish (finish_exploc),
830 m_range_display_kind (range_display_kind),
831- m_caret (*caret_exploc),
832+ m_caret (caret_exploc),
833 m_original_idx (original_idx),
834 m_label (label)
835 {
836@@ -646,6 +643,9 @@ layout_range::intersects_line_p (linenum
837
838 #if CHECKING_P
839
840+/* Default for when we don't care what the tab expansion is set to. */
841+static const int def_tabstop = 8;
842+
843 /* Create some expanded locations for testing layout_range. The filename
844 member of the explocs is set to the empty string. This member will only be
845 inspected by the calls to location_compute_display_column() made from the
846@@ -662,8 +662,11 @@ make_range (int start_line, int start_co
847 = {"", start_line, start_col, NULL, false};
848 const expanded_location finish_exploc
849 = {"", end_line, end_col, NULL, false};
850- return layout_range (&start_exploc, &finish_exploc, SHOW_RANGE_WITHOUT_CARET,
851- &start_exploc, 0, NULL);
852+ return layout_range (exploc_with_display_col (start_exploc, def_tabstop),
853+ exploc_with_display_col (finish_exploc, def_tabstop),
854+ SHOW_RANGE_WITHOUT_CARET,
855+ exploc_with_display_col (start_exploc, def_tabstop),
856+ 0, NULL);
857 }
858
859 /* Selftests for layout_range::contains_point and
860@@ -964,7 +967,7 @@ layout::layout (diagnostic_context * con
861 : m_context (context),
862 m_pp (context->printer),
863 m_primary_loc (richloc->get_range (0)->m_loc),
864- m_exploc (richloc->get_expanded_location (0)),
865+ m_exploc (richloc->get_expanded_location (0), context->tabstop),
866 m_colorizer (context, diagnostic_kind),
867 m_colorize_source_p (context->colorize_source_p),
868 m_show_labels_p (context->show_labels_p),
869@@ -1060,7 +1063,10 @@ layout::maybe_add_location_range (const
870
871 /* Everything is now known to be in the correct source file,
872 but it may require further sanitization. */
873- layout_range ri (&start, &finish, loc_range->m_range_display_kind, &caret,
874+ layout_range ri (exploc_with_display_col (start, m_context->tabstop),
875+ exploc_with_display_col (finish, m_context->tabstop),
876+ loc_range->m_range_display_kind,
877+ exploc_with_display_col (caret, m_context->tabstop),
878 original_idx, loc_range->m_label);
879
880 /* If we have a range that finishes before it starts (perhaps
881@@ -1394,7 +1400,7 @@ layout::calculate_x_offset_display ()
882 = get_line_bytes_without_trailing_whitespace (line.get_buffer (),
883 line.length ());
884 int eol_display_column
885- = cpp_display_width (line.get_buffer (), line_bytes);
886+ = cpp_display_width (line.get_buffer (), line_bytes, m_context->tabstop);
887 if (caret_display_column > eol_display_column
888 || !caret_display_column)
889 {
890@@ -1445,16 +1451,13 @@ layout::calculate_x_offset_display ()
891 }
892
893 /* Print line ROW of source code, potentially colorized at any ranges, and
894- populate *LBOUNDS_OUT.
895- LINE is the source line (not necessarily 0-terminated) and LINE_BYTES
896- is its length in bytes.
897- This function deals only with byte offsets, not display columns, so
898- m_x_offset_display must be converted from display to byte units. In
899- particular, LINE_BYTES and LBOUNDS_OUT are in bytes. */
900+ return the line bounds. LINE is the source line (not necessarily
901+ 0-terminated) and LINE_BYTES is its length in bytes. In order to handle both
902+ colorization and tab expansion, this function tracks the line position in
903+ both byte and display column units. */
904
905-void
906-layout::print_source_line (linenum_type row, const char *line, int line_bytes,
907- line_bounds *lbounds_out)
908+line_bounds
909+layout::print_source_line (linenum_type row, const char *line, int line_bytes)
910 {
911 m_colorizer.set_normal_text ();
912
913@@ -1469,30 +1472,29 @@ layout::print_source_line (linenum_type
914 else
915 pp_space (m_pp);
916
917- /* We will stop printing the source line at any trailing whitespace, and start
918- printing it as per m_x_offset_display. */
919+ /* We will stop printing the source line at any trailing whitespace. */
920 line_bytes = get_line_bytes_without_trailing_whitespace (line,
921 line_bytes);
922- int x_offset_bytes = 0;
923- if (m_x_offset_display)
924- {
925- x_offset_bytes = cpp_display_column_to_byte_column (line, line_bytes,
926- m_x_offset_display);
927- /* In case the leading portion of the line that will be skipped over ends
928- with a character with wcwidth > 1, then it is possible we skipped too
929- much, so account for that by padding with spaces. */
930- const int overage
931- = cpp_byte_column_to_display_column (line, line_bytes, x_offset_bytes)
932- - m_x_offset_display;
933- for (int column = 0; column < overage; ++column)
934- pp_space (m_pp);
935- line += x_offset_bytes;
936- }
937
938- /* Print the line. */
939- int first_non_ws = INT_MAX;
940- int last_non_ws = 0;
941- for (int col_byte = 1 + x_offset_bytes; col_byte <= line_bytes; col_byte++)
942+ /* This object helps to keep track of which display column we are at, which is
943+ necessary for computing the line bounds in display units, for doing
944+ tab expansion, and for implementing m_x_offset_display. */
945+ cpp_display_width_computation dw (line, line_bytes, m_context->tabstop);
946+
947+ /* Skip the first m_x_offset_display display columns. In case the leading
948+ portion that will be skipped ends with a character with wcwidth > 1, then
949+ it is possible we skipped too much, so account for that by padding with
950+ spaces. Note that this does the right thing too in case a tab was the last
951+ character to be skipped over; the tab is effectively replaced by the
952+ correct number of trailing spaces needed to offset by the desired number of
953+ display columns. */
954+ for (int skipped_display_cols = dw.advance_display_cols (m_x_offset_display);
955+ skipped_display_cols > m_x_offset_display; --skipped_display_cols)
956+ pp_space (m_pp);
957+
958+ /* Print the line and compute the line_bounds. */
959+ line_bounds lbounds;
960+ while (!dw.done ())
961 {
962 /* Assuming colorization is enabled for the caret and underline
963 characters, we may also colorize the associated characters
964@@ -1510,7 +1512,8 @@ layout::print_source_line (linenum_type
965 {
966 bool in_range_p;
967 point_state state;
968- in_range_p = get_state_at_point (row, col_byte,
969+ const int start_byte_col = dw.bytes_processed () + 1;
970+ in_range_p = get_state_at_point (row, start_byte_col,
971 0, INT_MAX,
972 CU_BYTES,
973 &state);
974@@ -1519,22 +1522,44 @@ layout::print_source_line (linenum_type
975 else
976 m_colorizer.set_normal_text ();
977 }
978- char c = *line;
979- if (c == '\0' || c == '\t' || c == '\r')
980- c = ' ';
981- if (c != ' ')
982+
983+ /* Get the display width of the next character to be output, expanding
984+ tabs and replacing some control bytes with spaces as necessary. */
985+ const char *c = dw.next_byte ();
986+ const int start_disp_col = dw.display_cols_processed () + 1;
987+ const int this_display_width = dw.process_next_codepoint ();
988+ if (*c == '\t')
989+ {
990+ /* The returned display width is the number of spaces into which the
991+ tab should be expanded. */
992+ for (int i = 0; i != this_display_width; ++i)
993+ pp_space (m_pp);
994+ continue;
995+ }
996+ if (*c == '\0' || *c == '\r')
997 {
998- last_non_ws = col_byte;
999- if (first_non_ws == INT_MAX)
1000- first_non_ws = col_byte;
1001+ /* cpp_wcwidth() promises to return 1 for all control bytes, and we
1002+ want to output these as a single space too, so this case is
1003+ actually the same as the '\t' case. */
1004+ gcc_assert (this_display_width == 1);
1005+ pp_space (m_pp);
1006+ continue;
1007 }
1008- pp_character (m_pp, c);
1009- line++;
1010+
1011+ /* We have a (possibly multibyte) character to output; update the line
1012+ bounds if it is not whitespace. */
1013+ if (*c != ' ')
1014+ {
1015+ lbounds.m_last_non_ws_disp_col = dw.display_cols_processed ();
1016+ if (lbounds.m_first_non_ws_disp_col == INT_MAX)
1017+ lbounds.m_first_non_ws_disp_col = start_disp_col;
1018+ }
1019+
1020+ /* Output the character. */
1021+ while (c != dw.next_byte ()) pp_character (m_pp, *c++);
1022 }
1023 print_newline ();
1024-
1025- lbounds_out->m_first_non_ws = first_non_ws;
1026- lbounds_out->m_last_non_ws = last_non_ws;
1027+ return lbounds;
1028 }
1029
1030 /* Determine if we should print an annotation line for ROW.
1031@@ -1576,14 +1601,13 @@ layout::start_annotation_line (char marg
1032 }
1033
1034 /* Print a line consisting of the caret/underlines for the given
1035- source line. This function works with display columns, rather than byte
1036- counts; in particular, LBOUNDS should be in display column units. */
1037+ source line. */
1038
1039 void
1040 layout::print_annotation_line (linenum_type row, const line_bounds lbounds)
1041 {
1042 int x_bound = get_x_bound_for_row (row, m_exploc.m_display_col,
1043- lbounds.m_last_non_ws);
1044+ lbounds.m_last_non_ws_disp_col);
1045
1046 start_annotation_line ();
1047 pp_space (m_pp);
1048@@ -1593,8 +1617,8 @@ layout::print_annotation_line (linenum_t
1049 bool in_range_p;
1050 point_state state;
1051 in_range_p = get_state_at_point (row, column,
1052- lbounds.m_first_non_ws,
1053- lbounds.m_last_non_ws,
1054+ lbounds.m_first_non_ws_disp_col,
1055+ lbounds.m_last_non_ws_disp_col,
1056 CU_DISPLAY_COLS,
1057 &state);
1058 if (in_range_p)
1059@@ -1631,12 +1655,14 @@ layout::print_annotation_line (linenum_t
1060 class line_label
1061 {
1062 public:
1063- line_label (int state_idx, int column, label_text text)
1064+ line_label (diagnostic_context *context, int state_idx, int column,
1065+ label_text text)
1066 : m_state_idx (state_idx), m_column (column),
1067 m_text (text), m_label_line (0), m_has_vbar (true)
1068 {
1069 const int bytes = strlen (text.m_buffer);
1070- m_display_width = cpp_display_width (text.m_buffer, bytes);
1071+ m_display_width
1072+ = cpp_display_width (text.m_buffer, bytes, context->tabstop);
1073 }
1074
1075 /* Sorting is primarily by column, then by state index. */
1076@@ -1696,7 +1722,7 @@ layout::print_any_labels (linenum_type r
1077 if (text.m_buffer == NULL)
1078 continue;
1079
1080- labels.safe_push (line_label (i, disp_col, text));
1081+ labels.safe_push (line_label (m_context, i, disp_col, text));
1082 }
1083 }
1084
1085@@ -1976,7 +2002,8 @@ public:
1086
1087 /* Get the range of bytes or display columns that HINT would affect. */
1088 static column_range
1089-get_affected_range (const fixit_hint *hint, enum column_unit col_unit)
1090+get_affected_range (diagnostic_context *context,
1091+ const fixit_hint *hint, enum column_unit col_unit)
1092 {
1093 expanded_location exploc_start = expand_location (hint->get_start_loc ());
1094 expanded_location exploc_finish = expand_location (hint->get_next_loc ());
1095@@ -1986,11 +2013,13 @@ get_affected_range (const fixit_hint *hi
1096 int finish_column;
1097 if (col_unit == CU_DISPLAY_COLS)
1098 {
1099- start_column = location_compute_display_column (exploc_start);
1100+ start_column
1101+ = location_compute_display_column (exploc_start, context->tabstop);
1102 if (hint->insertion_p ())
1103 finish_column = start_column - 1;
1104 else
1105- finish_column = location_compute_display_column (exploc_finish);
1106+ finish_column
1107+ = location_compute_display_column (exploc_finish, context->tabstop);
1108 }
1109 else
1110 {
1111@@ -2003,12 +2032,12 @@ get_affected_range (const fixit_hint *hi
1112 /* Get the range of display columns that would be printed for HINT. */
1113
1114 static column_range
1115-get_printed_columns (const fixit_hint *hint)
1116+get_printed_columns (diagnostic_context *context, const fixit_hint *hint)
1117 {
1118 expanded_location exploc = expand_location (hint->get_start_loc ());
1119- int start_column = location_compute_display_column (exploc);
1120- int hint_width = cpp_display_width (hint->get_string (),
1121- hint->get_length ());
1122+ int start_column = location_compute_display_column (exploc, context->tabstop);
1123+ int hint_width = cpp_display_width (hint->get_string (), hint->get_length (),
1124+ context->tabstop);
1125 int final_hint_column = start_column + hint_width - 1;
1126 if (hint->insertion_p ())
1127 {
1128@@ -2018,7 +2047,8 @@ get_printed_columns (const fixit_hint *h
1129 {
1130 exploc = expand_location (hint->get_next_loc ());
1131 --exploc.column;
1132- int finish_column = location_compute_display_column (exploc);
1133+ int finish_column
1134+ = location_compute_display_column (exploc, context->tabstop);
1135 return column_range (start_column,
1136 MAX (finish_column, final_hint_column));
1137 }
1138@@ -2035,12 +2065,14 @@ public:
1139 correction (column_range affected_bytes,
1140 column_range affected_columns,
1141 column_range printed_columns,
1142- const char *new_text, size_t new_text_len)
1143+ const char *new_text, size_t new_text_len,
1144+ int tabstop)
1145 : m_affected_bytes (affected_bytes),
1146 m_affected_columns (affected_columns),
1147 m_printed_columns (printed_columns),
1148 m_text (xstrdup (new_text)),
1149 m_byte_length (new_text_len),
1150+ m_tabstop (tabstop),
1151 m_alloc_sz (new_text_len + 1)
1152 {
1153 compute_display_cols ();
1154@@ -2058,7 +2090,7 @@ public:
1155
1156 void compute_display_cols ()
1157 {
1158- m_display_cols = cpp_display_width (m_text, m_byte_length);
1159+ m_display_cols = cpp_display_width (m_text, m_byte_length, m_tabstop);
1160 }
1161
1162 void overwrite (int dst_offset, const char_span &src_span)
1163@@ -2086,6 +2118,7 @@ public:
1164 char *m_text;
1165 size_t m_byte_length; /* Not including null-terminator. */
1166 int m_display_cols;
1167+ int m_tabstop;
1168 size_t m_alloc_sz;
1169 };
1170
1171@@ -2121,13 +2154,15 @@ correction::ensure_terminated ()
1172 class line_corrections
1173 {
1174 public:
1175- line_corrections (const char *filename, linenum_type row)
1176- : m_filename (filename), m_row (row)
1177+ line_corrections (diagnostic_context *context, const char *filename,
1178+ linenum_type row)
1179+ : m_context (context), m_filename (filename), m_row (row)
1180 {}
1181 ~line_corrections ();
1182
1183 void add_hint (const fixit_hint *hint);
1184
1185+ diagnostic_context *m_context;
1186 const char *m_filename;
1187 linenum_type m_row;
1188 auto_vec <correction *> m_corrections;
1189@@ -2173,9 +2208,10 @@ source_line::source_line (const char *fi
1190 void
1191 line_corrections::add_hint (const fixit_hint *hint)
1192 {
1193- column_range affected_bytes = get_affected_range (hint, CU_BYTES);
1194- column_range affected_columns = get_affected_range (hint, CU_DISPLAY_COLS);
1195- column_range printed_columns = get_printed_columns (hint);
1196+ column_range affected_bytes = get_affected_range (m_context, hint, CU_BYTES);
1197+ column_range affected_columns = get_affected_range (m_context, hint,
1198+ CU_DISPLAY_COLS);
1199+ column_range printed_columns = get_printed_columns (m_context, hint);
1200
1201 /* Potentially consolidate. */
1202 if (!m_corrections.is_empty ())
1203@@ -2243,7 +2279,8 @@ line_corrections::add_hint (const fixit_
1204 affected_columns,
1205 printed_columns,
1206 hint->get_string (),
1207- hint->get_length ()));
1208+ hint->get_length (),
1209+ m_context->tabstop));
1210 }
1211
1212 /* If there are any fixit hints on source line ROW, print them.
1213@@ -2257,7 +2294,7 @@ layout::print_trailing_fixits (linenum_t
1214 {
1215 /* Build a list of correction instances for the line,
1216 potentially consolidating hints (for the sake of readability). */
1217- line_corrections corrections (m_exploc.file, row);
1218+ line_corrections corrections (m_context, m_exploc.file, row);
1219 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
1220 {
1221 const fixit_hint *hint = m_fixit_hints[i];
1222@@ -2499,15 +2536,11 @@ layout::print_line (linenum_type row)
1223 if (!line)
1224 return;
1225
1226- line_bounds lbounds;
1227 print_leading_fixits (row);
1228- print_source_line (row, line.get_buffer (), line.length (), &lbounds);
1229+ const line_bounds lbounds
1230+ = print_source_line (row, line.get_buffer (), line.length ());
1231 if (should_print_annotation_line_p (row))
1232- {
1233- if (lbounds.m_first_non_ws != INT_MAX)
1234- lbounds.convert_to_display_cols (line);
1235- print_annotation_line (row, lbounds);
1236- }
1237+ print_annotation_line (row, lbounds);
1238 if (m_show_labels_p)
1239 print_any_labels (row);
1240 print_trailing_fixits (row);
1241@@ -2670,9 +2703,11 @@ test_layout_x_offset_display_utf8 (const
1242
1243 char_span lspan = location_get_source_line (tmp.get_filename (), 1);
1244 ASSERT_EQ (line_display_cols,
1245- cpp_display_width (lspan.get_buffer (), lspan.length ()));
1246+ cpp_display_width (lspan.get_buffer (), lspan.length (),
1247+ def_tabstop));
1248 ASSERT_EQ (line_display_cols,
1249- location_compute_display_column (expand_location (line_end)));
1250+ location_compute_display_column (expand_location (line_end),
1251+ def_tabstop));
1252 ASSERT_EQ (0, memcmp (lspan.get_buffer () + (emoji_col - 1),
1253 "\xf0\x9f\x98\x82\xf0\x9f\x98\x82", 8));
1254
1255@@ -2774,6 +2809,111 @@ test_layout_x_offset_display_utf8 (const
1256
1257 }
1258
1259+static void
1260+test_layout_x_offset_display_tab (const line_table_case &case_)
1261+{
1262+ const char *content
1263+ = "This line is very long, so that we can use it to test the logic for "
1264+ "clipping long lines. Also this: `\t' is a tab that occupies 1 byte and "
1265+ "a variable number of display columns, starting at column #103.\n";
1266+
1267+ /* Number of bytes in the line, subtracting one to remove the newline. */
1268+ const int line_bytes = strlen (content) - 1;
1269+
1270+ /* The column where the tab begins. Byte or display is the same as there are
1271+ no multibyte characters earlier on the line. */
1272+ const int tab_col = 103;
1273+
1274+ /* Effective extra size of the tab beyond what a single space would have taken
1275+ up, indexed by tabstop. */
1276+ static const int num_tabstops = 11;
1277+ int extra_width[num_tabstops];
1278+ for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
1279+ {
1280+ const int this_tab_size = tabstop - (tab_col - 1) % tabstop;
1281+ extra_width[tabstop] = this_tab_size - 1;
1282+ }
1283+ /* Example of this calculation: if tabstop is 10, the tab starting at column
1284+ #103 has to expand into 8 spaces, covering columns 103-110, so that the
1285+ next character is at column #111. So it takes up 7 more columns than
1286+ a space would have taken up. */
1287+ ASSERT_EQ (7, extra_width[10]);
1288+
1289+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
1290+ line_table_test ltt (case_);
1291+
1292+ linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
1293+
1294+ location_t line_end = linemap_position_for_column (line_table, line_bytes);
1295+
1296+ /* Don't attempt to run the tests if column data might be unavailable. */
1297+ if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
1298+ return;
1299+
1300+ /* Check that cpp_display_width handles the tabs as expected. */
1301+ char_span lspan = location_get_source_line (tmp.get_filename (), 1);
1302+ ASSERT_EQ ('\t', *(lspan.get_buffer () + (tab_col - 1)));
1303+ for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
1304+ {
1305+ ASSERT_EQ (line_bytes + extra_width[tabstop],
1306+ cpp_display_width (lspan.get_buffer (), lspan.length (),
1307+ tabstop));
1308+ ASSERT_EQ (line_bytes + extra_width[tabstop],
1309+ location_compute_display_column (expand_location (line_end),
1310+ tabstop));
1311+ }
1312+
1313+ /* Check that the tab is expanded to the expected number of spaces. */
1314+ rich_location richloc (line_table,
1315+ linemap_position_for_column (line_table,
1316+ tab_col + 1));
1317+ for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
1318+ {
1319+ test_diagnostic_context dc;
1320+ dc.tabstop = tabstop;
1321+ layout test_layout (&dc, &richloc, DK_ERROR);
1322+ test_layout.print_line (1);
1323+ const char *out = pp_formatted_text (dc.printer);
1324+ ASSERT_EQ (NULL, strchr (out, '\t'));
1325+ const char *left_quote = strchr (out, '`');
1326+ const char *right_quote = strchr (out, '\'');
1327+ ASSERT_NE (NULL, left_quote);
1328+ ASSERT_NE (NULL, right_quote);
1329+ ASSERT_EQ (right_quote - left_quote, extra_width[tabstop] + 2);
1330+ }
1331+
1332+ /* Check that the line is offset properly and that the tab is broken up
1333+ into the expected number of spaces when it is the last character skipped
1334+ over. */
1335+ for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
1336+ {
1337+ test_diagnostic_context dc;
1338+ dc.tabstop = tabstop;
1339+ static const int small_width = 24;
1340+ dc.caret_max_width = small_width - 4;
1341+ dc.min_margin_width = test_left_margin - test_linenum_sep + 1;
1342+ dc.show_line_numbers_p = true;
1343+ layout test_layout (&dc, &richloc, DK_ERROR);
1344+ test_layout.print_line (1);
1345+
1346+ /* We have arranged things so that two columns will be printed before
1347+ the caret. If the tab results in more than one space, this should
1348+ produce two spaces in the output; otherwise, it will be a single space
1349+ preceded by the opening quote before the tab character. */
1350+ const char *output1
1351+ = " 1 | ' is a tab that occupies 1 byte and a variable number of "
1352+ "display columns, starting at column #103.\n"
1353+ " | ^\n\n";
1354+ const char *output2
1355+ = " 1 | ` ' is a tab that occupies 1 byte and a variable number of "
1356+ "display columns, starting at column #103.\n"
1357+ " | ^\n\n";
1358+ const char *expected_output = (extra_width[tabstop] ? output1 : output2);
1359+ ASSERT_STREQ (expected_output, pp_formatted_text (dc.printer));
1360+ }
1361+}
1362+
1363+
1364 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
1365
1366 static void
1367@@ -3854,6 +3994,27 @@ test_one_liner_labels_utf8 ()
1368 }
1369 }
1370
1371+/* Make sure that colorization codes don't interrupt a multibyte
1372+ sequence, which would corrupt it. */
1373+static void
1374+test_one_liner_colorized_utf8 ()
1375+{
1376+ test_diagnostic_context dc;
1377+ dc.colorize_source_p = true;
1378+ diagnostic_color_init (&dc, DIAGNOSTICS_COLOR_YES);
1379+ const location_t pi = linemap_position_for_column (line_table, 12);
1380+ rich_location richloc (line_table, pi);
1381+ diagnostic_show_locus (&dc, &richloc, DK_ERROR);
1382+
1383+ /* In order to avoid having the test depend on exactly how the colorization
1384+ was effected, just confirm there are two pi characters in the output. */
1385+ const char *result = pp_formatted_text (dc.printer);
1386+ const char *null_term = result + strlen (result);
1387+ const char *first_pi = strstr (result, "\xcf\x80");
1388+ ASSERT_TRUE (first_pi && first_pi <= null_term - 2);
1389+ ASSERT_STR_CONTAINS (first_pi + 2, "\xcf\x80");
1390+}
1391+
1392 /* Run the various one-liner tests. */
1393
1394 static void
1395@@ -3884,8 +4045,10 @@ test_diagnostic_show_locus_one_liner_utf
1396 ASSERT_EQ (31, LOCATION_COLUMN (line_end));
1397
1398 char_span lspan = location_get_source_line (tmp.get_filename (), 1);
1399- ASSERT_EQ (25, cpp_display_width (lspan.get_buffer (), lspan.length ()));
1400- ASSERT_EQ (25, location_compute_display_column (expand_location (line_end)));
1401+ ASSERT_EQ (25, cpp_display_width (lspan.get_buffer (), lspan.length (),
1402+ def_tabstop));
1403+ ASSERT_EQ (25, location_compute_display_column (expand_location (line_end),
1404+ def_tabstop));
1405
1406 test_one_liner_simple_caret_utf8 ();
1407 test_one_liner_caret_and_range_utf8 ();
1408@@ -3900,6 +4063,7 @@ test_diagnostic_show_locus_one_liner_utf
1409 test_one_liner_many_fixits_1_utf8 ();
1410 test_one_liner_many_fixits_2_utf8 ();
1411 test_one_liner_labels_utf8 ();
1412+ test_one_liner_colorized_utf8 ();
1413 }
1414
1415 /* Verify that gcc_rich_location::add_location_if_nearby works. */
1416@@ -4272,25 +4436,28 @@ test_overlapped_fixit_printing (const li
1417 /* Unit-test the line_corrections machinery. */
1418 ASSERT_EQ (3, richloc.get_num_fixit_hints ());
1419 const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
1420- ASSERT_EQ (column_range (12, 12), get_affected_range (hint_0, CU_BYTES));
1421 ASSERT_EQ (column_range (12, 12),
1422- get_affected_range (hint_0, CU_DISPLAY_COLS));
1423- ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0));
1424+ get_affected_range (&dc, hint_0, CU_BYTES));
1425+ ASSERT_EQ (column_range (12, 12),
1426+ get_affected_range (&dc, hint_0, CU_DISPLAY_COLS));
1427+ ASSERT_EQ (column_range (12, 22), get_printed_columns (&dc, hint_0));
1428 const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
1429- ASSERT_EQ (column_range (18, 18), get_affected_range (hint_1, CU_BYTES));
1430 ASSERT_EQ (column_range (18, 18),
1431- get_affected_range (hint_1, CU_DISPLAY_COLS));
1432- ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1));
1433+ get_affected_range (&dc, hint_1, CU_BYTES));
1434+ ASSERT_EQ (column_range (18, 18),
1435+ get_affected_range (&dc, hint_1, CU_DISPLAY_COLS));
1436+ ASSERT_EQ (column_range (18, 20), get_printed_columns (&dc, hint_1));
1437 const fixit_hint *hint_2 = richloc.get_fixit_hint (2);
1438- ASSERT_EQ (column_range (29, 28), get_affected_range (hint_2, CU_BYTES));
1439 ASSERT_EQ (column_range (29, 28),
1440- get_affected_range (hint_2, CU_DISPLAY_COLS));
1441- ASSERT_EQ (column_range (29, 29), get_printed_columns (hint_2));
1442+ get_affected_range (&dc, hint_2, CU_BYTES));
1443+ ASSERT_EQ (column_range (29, 28),
1444+ get_affected_range (&dc, hint_2, CU_DISPLAY_COLS));
1445+ ASSERT_EQ (column_range (29, 29), get_printed_columns (&dc, hint_2));
1446
1447 /* Add each hint in turn to a line_corrections instance,
1448 and verify that they are consolidated into one correction instance
1449 as expected. */
1450- line_corrections lc (tmp.get_filename (), 1);
1451+ line_corrections lc (&dc, tmp.get_filename (), 1);
1452
1453 /* The first replace hint by itself. */
1454 lc.add_hint (hint_0);
1455@@ -4484,25 +4651,28 @@ test_overlapped_fixit_printing_utf8 (con
1456 /* Unit-test the line_corrections machinery. */
1457 ASSERT_EQ (3, richloc.get_num_fixit_hints ());
1458 const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
1459- ASSERT_EQ (column_range (14, 14), get_affected_range (hint_0, CU_BYTES));
1460+ ASSERT_EQ (column_range (14, 14),
1461+ get_affected_range (&dc, hint_0, CU_BYTES));
1462 ASSERT_EQ (column_range (12, 12),
1463- get_affected_range (hint_0, CU_DISPLAY_COLS));
1464- ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0));
1465+ get_affected_range (&dc, hint_0, CU_DISPLAY_COLS));
1466+ ASSERT_EQ (column_range (12, 22), get_printed_columns (&dc, hint_0));
1467 const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
1468- ASSERT_EQ (column_range (22, 22), get_affected_range (hint_1, CU_BYTES));
1469+ ASSERT_EQ (column_range (22, 22),
1470+ get_affected_range (&dc, hint_1, CU_BYTES));
1471 ASSERT_EQ (column_range (18, 18),
1472- get_affected_range (hint_1, CU_DISPLAY_COLS));
1473- ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1));
1474+ get_affected_range (&dc, hint_1, CU_DISPLAY_COLS));
1475+ ASSERT_EQ (column_range (18, 20), get_printed_columns (&dc, hint_1));
1476 const fixit_hint *hint_2 = richloc.get_fixit_hint (2);
1477- ASSERT_EQ (column_range (35, 34), get_affected_range (hint_2, CU_BYTES));
1478+ ASSERT_EQ (column_range (35, 34),
1479+ get_affected_range (&dc, hint_2, CU_BYTES));
1480 ASSERT_EQ (column_range (30, 29),
1481- get_affected_range (hint_2, CU_DISPLAY_COLS));
1482- ASSERT_EQ (column_range (30, 30), get_printed_columns (hint_2));
1483+ get_affected_range (&dc, hint_2, CU_DISPLAY_COLS));
1484+ ASSERT_EQ (column_range (30, 30), get_printed_columns (&dc, hint_2));
1485
1486 /* Add each hint in turn to a line_corrections instance,
1487 and verify that they are consolidated into one correction instance
1488 as expected. */
1489- line_corrections lc (tmp.get_filename (), 1);
1490+ line_corrections lc (&dc, tmp.get_filename (), 1);
1491
1492 /* The first replace hint by itself. */
1493 lc.add_hint (hint_0);
1494@@ -4689,6 +4859,8 @@ test_overlapped_fixit_printing_2 (const
1495
1496 /* Two insertions, in the wrong order. */
1497 {
1498+ test_diagnostic_context dc;
1499+
1500 rich_location richloc (line_table, col_20);
1501 richloc.add_fixit_insert_before (col_23, "{");
1502 richloc.add_fixit_insert_before (col_21, "}");
1503@@ -4696,14 +4868,15 @@ test_overlapped_fixit_printing_2 (const
1504 /* These fixits should be accepted; they can't be consolidated. */
1505 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
1506 const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
1507- ASSERT_EQ (column_range (23, 22), get_affected_range (hint_0, CU_BYTES));
1508- ASSERT_EQ (column_range (23, 23), get_printed_columns (hint_0));
1509+ ASSERT_EQ (column_range (23, 22),
1510+ get_affected_range (&dc, hint_0, CU_BYTES));
1511+ ASSERT_EQ (column_range (23, 23), get_printed_columns (&dc, hint_0));
1512 const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
1513- ASSERT_EQ (column_range (21, 20), get_affected_range (hint_1, CU_BYTES));
1514- ASSERT_EQ (column_range (21, 21), get_printed_columns (hint_1));
1515+ ASSERT_EQ (column_range (21, 20),
1516+ get_affected_range (&dc, hint_1, CU_BYTES));
1517+ ASSERT_EQ (column_range (21, 21), get_printed_columns (&dc, hint_1));
1518
1519 /* Verify that they're printed correctly. */
1520- test_diagnostic_context dc;
1521 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
1522 ASSERT_STREQ (" int a5[][0][0] = { 1, 2 };\n"
1523 " ^\n"
1524@@ -4955,6 +5128,65 @@ test_fixit_deletion_affecting_newline (c
1525 pp_formatted_text (dc.printer));
1526 }
1527
1528+static void
1529+test_tab_expansion (const line_table_case &case_)
1530+{
1531+ /* Create a tempfile and write some text to it. This example uses a tabstop
1532+ of 8, as the column numbers attempt to indicate:
1533+
1534+ .....................000.01111111111.22222333333 display
1535+ .....................123.90123456789.56789012345 columns */
1536+ const char *content = " \t This: `\t' is a tab.\n";
1537+ /* ....................000 00000011111 11111222222 byte
1538+ ....................123 45678901234 56789012345 columns */
1539+
1540+ const int tabstop = 8;
1541+ const int first_non_ws_byte_col = 7;
1542+ const int right_quote_byte_col = 15;
1543+ const int last_byte_col = 25;
1544+ ASSERT_EQ (35, cpp_display_width (content, last_byte_col, tabstop));
1545+
1546+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
1547+ line_table_test ltt (case_);
1548+ linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
1549+
1550+ /* Don't attempt to run the tests if column data might be unavailable. */
1551+ location_t line_end = linemap_position_for_column (line_table, last_byte_col);
1552+ if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
1553+ return;
1554+
1555+ /* Check that the leading whitespace with mixed tabs and spaces is expanded
1556+ into 11 spaces. Recall that print_line() also puts one space before
1557+ everything too. */
1558+ {
1559+ test_diagnostic_context dc;
1560+ dc.tabstop = tabstop;
1561+ rich_location richloc (line_table,
1562+ linemap_position_for_column (line_table,
1563+ first_non_ws_byte_col));
1564+ layout test_layout (&dc, &richloc, DK_ERROR);
1565+ test_layout.print_line (1);
1566+ ASSERT_STREQ (" This: ` ' is a tab.\n"
1567+ " ^\n",
1568+ pp_formatted_text (dc.printer));
1569+ }
1570+
1571+ /* Confirm the display width was tracked correctly across the internal tab
1572+ as well. */
1573+ {
1574+ test_diagnostic_context dc;
1575+ dc.tabstop = tabstop;
1576+ rich_location richloc (line_table,
1577+ linemap_position_for_column (line_table,
1578+ right_quote_byte_col));
1579+ layout test_layout (&dc, &richloc, DK_ERROR);
1580+ test_layout.print_line (1);
1581+ ASSERT_STREQ (" This: ` ' is a tab.\n"
1582+ " ^\n",
1583+ pp_formatted_text (dc.printer));
1584+ }
1585+}
1586+
1587 /* Verify that line numbers are correctly printed for the case of
1588 a multiline range in which the width of the line numbers changes
1589 (e.g. from "9" to "10"). */
1590@@ -5012,6 +5244,7 @@ diagnostic_show_locus_c_tests ()
1591 test_layout_range_for_multiple_lines ();
1592
1593 for_each_line_table_case (test_layout_x_offset_display_utf8);
1594+ for_each_line_table_case (test_layout_x_offset_display_tab);
1595
1596 test_get_line_bytes_without_trailing_whitespace ();
1597
1598@@ -5029,6 +5262,7 @@ diagnostic_show_locus_c_tests ()
1599 for_each_line_table_case (test_fixit_insert_containing_newline_2);
1600 for_each_line_table_case (test_fixit_replace_containing_newline);
1601 for_each_line_table_case (test_fixit_deletion_affecting_newline);
1602+ for_each_line_table_case (test_tab_expansion);
1603
1604 test_line_numbers_multiline_range ();
1605 }
1606diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
1607--- a/gcc/doc/invoke.texi 2021-12-24 20:23:46.876739587 -0800
1608+++ b/gcc/doc/invoke.texi 2021-12-25 01:20:53.487636494 -0800
1609@@ -293,7 +293,9 @@ Objective-C and Objective-C++ Dialects}.
1610 -fdiagnostics-show-template-tree -fno-elide-type @gol
1611 -fdiagnostics-path-format=@r{[}none@r{|}separate-events@r{|}inline-events@r{]} @gol
1612 -fdiagnostics-show-path-depths @gol
1613--fno-show-column}
1614+-fno-show-column @gol
1615+-fdiagnostics-column-unit=@r{[}display@r{|}byte@r{]} @gol
1616+-fdiagnostics-column-origin=@var{origin}}
1617
1618 @item Warning Options
1619 @xref{Warning Options,,Options to Request or Suppress Warnings}.
1620@@ -4424,6 +4426,31 @@ Do not print column numbers in diagnosti
1621 diagnostics are being scanned by a program that does not understand the
1622 column numbers, such as @command{dejagnu}.
1623
1624+@item -fdiagnostics-column-unit=@var{UNIT}
1625+@opindex fdiagnostics-column-unit
1626+Select the units for the column number. This affects traditional diagnostics
1627+(in the absence of @option{-fno-show-column}), as well as JSON format
1628+diagnostics if requested.
1629+
1630+The default @var{UNIT}, @samp{display}, considers the number of display
1631+columns occupied by each character. This may be larger than the number
1632+of bytes required to encode the character, in the case of tab
1633+characters, or it may be smaller, in the case of multibyte characters.
1634+For example, the character ``GREEK SMALL LETTER PI (U+03C0)'' occupies one
1635+display column, and its UTF-8 encoding requires two bytes; the character
1636+``SLIGHTLY SMILING FACE (U+1F642)'' occupies two display columns, and
1637+its UTF-8 encoding requires four bytes.
1638+
1639+Setting @var{UNIT} to @samp{byte} changes the column number to the raw byte
1640+count in all cases, as was traditionally output by GCC prior to version 11.1.0.
1641+
1642+@item -fdiagnostics-column-origin=@var{ORIGIN}
1643+@opindex fdiagnostics-column-origin
1644+Select the origin for column numbers, i.e. the column number assigned to the
1645+first column. The default value of 1 corresponds to traditional GCC
1646+behavior and to the GNU style guide. Some utilities may perform better with an
1647+origin of 0; any non-negative value may be specified.
1648+
1649 @item -fdiagnostics-format=@var{FORMAT}
1650 @opindex fdiagnostics-format
1651 Select a different format for printing diagnostics.
1652@@ -4459,11 +4486,15 @@ might be printed in JSON form (after for
1653 "locations": [
1654 @{
1655 "caret": @{
1656+ "display-column": 3,
1657+ "byte-column": 3,
1658 "column": 3,
1659 "file": "misleading-indentation.c",
1660 "line": 15
1661 @},
1662 "finish": @{
1663+ "display-column": 4,
1664+ "byte-column": 4,
1665 "column": 4,
1666 "file": "misleading-indentation.c",
1667 "line": 15
1668@@ -4479,6 +4510,8 @@ might be printed in JSON form (after for
1669 "locations": [
1670 @{
1671 "caret": @{
1672+ "display-column": 5,
1673+ "byte-column": 5,
1674 "column": 5,
1675 "file": "misleading-indentation.c",
1676 "line": 17
1677@@ -4488,6 +4521,7 @@ might be printed in JSON form (after for
1678 "message": "...this statement, but the latter is @dots{}"
1679 @}
1680 ]
1681+ "column-origin": 1,
1682 @},
1683 @dots{}
1684 ]
1685@@ -4500,10 +4534,34 @@ A diagnostic has a @code{kind}. If this
1686 an @code{option} key describing the command-line option controlling the
1687 warning.
1688
1689-A diagnostic can contain zero or more locations. Each location has up
1690-to three positions within it: a @code{caret} position and optional
1691-@code{start} and @code{finish} positions. A location can also have
1692-an optional @code{label} string. For example, this error:
1693+A diagnostic can contain zero or more locations. Each location has an
1694+optional @code{label} string and up to three positions within it: a
1695+@code{caret} position and optional @code{start} and @code{finish} positions.
1696+A position is described by a @code{file} name, a @code{line} number, and
1697+three numbers indicating a column position:
1698+@itemize @bullet
1699+
1700+@item
1701+@code{display-column} counts display columns, accounting for tabs and
1702+multibyte characters.
1703+
1704+@item
1705+@code{byte-column} counts raw bytes.
1706+
1707+@item
1708+@code{column} is equal to one of
1709+the previous two, as dictated by the @option{-fdiagnostics-column-unit}
1710+option.
1711+
1712+@end itemize
1713+All three columns are relative to the origin specified by
1714+@option{-fdiagnostics-column-origin}, which is typically equal to 1 but may
1715+be set, for instance, to 0 for compatibility with other utilities that
1716+number columns from 0. The column origin is recorded in the JSON output in
1717+the @code{column-origin} tag. In the remaining examples below, the extra
1718+column number outputs have been omitted for brevity.
1719+
1720+For example, this error:
1721
1722 @smallexample
1723 bad-binary-ops.c:64:23: error: invalid operands to binary + (have 'S' @{aka
1724diff --git a/gcc/input.c b/gcc/input.c
1725--- a/gcc/input.c 2020-07-22 23:35:17.664388078 -0700
1726+++ b/gcc/input.c 2021-12-25 01:20:53.487636494 -0800
1727@@ -913,7 +913,7 @@ make_location (location_t caret, source_
1728 source line in order to calculate the display width. If that cannot be done
1729 for any reason, then returns the byte column as a fallback. */
1730 int
1731-location_compute_display_column (expanded_location exploc)
1732+location_compute_display_column (expanded_location exploc, int tabstop)
1733 {
1734 if (!(exploc.file && *exploc.file && exploc.line && exploc.column))
1735 return exploc.column;
1736@@ -921,7 +921,7 @@ location_compute_display_column (expande
1737 /* If line is NULL, this function returns exploc.column which is the
1738 desired fallback. */
1739 return cpp_byte_column_to_display_column (line.get_buffer (), line.length (),
1740- exploc.column);
1741+ exploc.column, tabstop);
1742 }
1743
1744 /* Dump statistics to stderr about the memory usage of the line_table
1745@@ -3608,33 +3608,46 @@ test_line_offset_overflow ()
1746
1747 void test_cpp_utf8 ()
1748 {
1749+ const int def_tabstop = 8;
1750 /* Verify that wcwidth of invalid UTF-8 or control bytes is 1. */
1751 {
1752- int w_bad = cpp_display_width ("\xf0!\x9f!\x98!\x82!", 8);
1753+ int w_bad = cpp_display_width ("\xf0!\x9f!\x98!\x82!", 8, def_tabstop);
1754 ASSERT_EQ (8, w_bad);
1755- int w_ctrl = cpp_display_width ("\r\t\n\v\0\1", 6);
1756- ASSERT_EQ (6, w_ctrl);
1757+ int w_ctrl = cpp_display_width ("\r\n\v\0\1", 5, def_tabstop);
1758+ ASSERT_EQ (5, w_ctrl);
1759 }
1760
1761 /* Verify that wcwidth of valid UTF-8 is as expected. */
1762 {
1763- const int w_pi = cpp_display_width ("\xcf\x80", 2);
1764+ const int w_pi = cpp_display_width ("\xcf\x80", 2, def_tabstop);
1765 ASSERT_EQ (1, w_pi);
1766- const int w_emoji = cpp_display_width ("\xf0\x9f\x98\x82", 4);
1767+ const int w_emoji = cpp_display_width ("\xf0\x9f\x98\x82", 4, def_tabstop);
1768 ASSERT_EQ (2, w_emoji);
1769- const int w_umlaut_precomposed = cpp_display_width ("\xc3\xbf", 2);
1770+ const int w_umlaut_precomposed = cpp_display_width ("\xc3\xbf", 2,
1771+ def_tabstop);
1772 ASSERT_EQ (1, w_umlaut_precomposed);
1773- const int w_umlaut_combining = cpp_display_width ("y\xcc\x88", 3);
1774+ const int w_umlaut_combining = cpp_display_width ("y\xcc\x88", 3,
1775+ def_tabstop);
1776 ASSERT_EQ (1, w_umlaut_combining);
1777- const int w_han = cpp_display_width ("\xe4\xb8\xba", 3);
1778+ const int w_han = cpp_display_width ("\xe4\xb8\xba", 3, def_tabstop);
1779 ASSERT_EQ (2, w_han);
1780- const int w_ascii = cpp_display_width ("GCC", 3);
1781+ const int w_ascii = cpp_display_width ("GCC", 3, def_tabstop);
1782 ASSERT_EQ (3, w_ascii);
1783 const int w_mixed = cpp_display_width ("\xcf\x80 = 3.14 \xf0\x9f\x98\x82"
1784- "\x9f! \xe4\xb8\xba y\xcc\x88", 24);
1785+ "\x9f! \xe4\xb8\xba y\xcc\x88",
1786+ 24, def_tabstop);
1787 ASSERT_EQ (18, w_mixed);
1788 }
1789
1790+ /* Verify that display width properly expands tabs. */
1791+ {
1792+ const char *tstr = "\tabc\td";
1793+ ASSERT_EQ (6, cpp_display_width (tstr, 6, 1));
1794+ ASSERT_EQ (10, cpp_display_width (tstr, 6, 3));
1795+ ASSERT_EQ (17, cpp_display_width (tstr, 6, 8));
1796+ ASSERT_EQ (1, cpp_display_column_to_byte_column (tstr, 6, 7, 8));
1797+ }
1798+
1799 /* Verify that cpp_byte_column_to_display_column can go past the end,
1800 and similar edge cases. */
1801 {
1802@@ -3645,10 +3658,13 @@ void test_cpp_utf8 ()
1803 /* 111122223456
1804 Byte columns. */
1805
1806- ASSERT_EQ (5, cpp_display_width (str, 6));
1807- ASSERT_EQ (105, cpp_byte_column_to_display_column (str, 6, 106));
1808- ASSERT_EQ (10000, cpp_byte_column_to_display_column (NULL, 0, 10000));
1809- ASSERT_EQ (0, cpp_byte_column_to_display_column (NULL, 10000, 0));
1810+ ASSERT_EQ (5, cpp_display_width (str, 6, def_tabstop));
1811+ ASSERT_EQ (105,
1812+ cpp_byte_column_to_display_column (str, 6, 106, def_tabstop));
1813+ ASSERT_EQ (10000,
1814+ cpp_byte_column_to_display_column (NULL, 0, 10000, def_tabstop));
1815+ ASSERT_EQ (0,
1816+ cpp_byte_column_to_display_column (NULL, 10000, 0, def_tabstop));
1817 }
1818
1819 /* Verify that cpp_display_column_to_byte_column can go past the end,
1820@@ -3662,21 +3678,25 @@ void test_cpp_utf8 ()
1821 /* 000000000000000000000000000000000111111
1822 111122223333444456666777788889999012345
1823 Byte columns. */
1824- ASSERT_EQ (4, cpp_display_column_to_byte_column (str, 15, 2));
1825- ASSERT_EQ (15, cpp_display_column_to_byte_column (str, 15, 11));
1826- ASSERT_EQ (115, cpp_display_column_to_byte_column (str, 15, 111));
1827- ASSERT_EQ (10000, cpp_display_column_to_byte_column (NULL, 0, 10000));
1828- ASSERT_EQ (0, cpp_display_column_to_byte_column (NULL, 10000, 0));
1829+ ASSERT_EQ (4, cpp_display_column_to_byte_column (str, 15, 2, def_tabstop));
1830+ ASSERT_EQ (15,
1831+ cpp_display_column_to_byte_column (str, 15, 11, def_tabstop));
1832+ ASSERT_EQ (115,
1833+ cpp_display_column_to_byte_column (str, 15, 111, def_tabstop));
1834+ ASSERT_EQ (10000,
1835+ cpp_display_column_to_byte_column (NULL, 0, 10000, def_tabstop));
1836+ ASSERT_EQ (0,
1837+ cpp_display_column_to_byte_column (NULL, 10000, 0, def_tabstop));
1838
1839 /* Verify that we do not interrupt a UTF-8 sequence. */
1840- ASSERT_EQ (4, cpp_display_column_to_byte_column (str, 15, 1));
1841+ ASSERT_EQ (4, cpp_display_column_to_byte_column (str, 15, 1, def_tabstop));
1842
1843 for (int byte_col = 1; byte_col <= 15; ++byte_col)
1844 {
1845- const int disp_col = cpp_byte_column_to_display_column (str, 15,
1846- byte_col);
1847- const int byte_col2 = cpp_display_column_to_byte_column (str, 15,
1848- disp_col);
1849+ const int disp_col
1850+ = cpp_byte_column_to_display_column (str, 15, byte_col, def_tabstop);
1851+ const int byte_col2
1852+ = cpp_display_column_to_byte_column (str, 15, disp_col, def_tabstop);
1853
1854 /* If we ask for the display column in the middle of a UTF-8
1855 sequence, it will return the length of the partial sequence,
1856diff --git a/gcc/input.h b/gcc/input.h
1857--- a/gcc/input.h 2020-07-22 23:35:17.664388078 -0700
1858+++ b/gcc/input.h 2021-12-25 01:20:53.487636494 -0800
1859@@ -38,7 +38,9 @@ STATIC_ASSERT (BUILTINS_LOCATION < RESER
1860
1861 extern bool is_location_from_builtin_token (location_t);
1862 extern expanded_location expand_location (location_t);
1863-extern int location_compute_display_column (expanded_location);
1864+
1865+extern int location_compute_display_column (expanded_location exploc,
1866+ int tabstop);
1867
1868 /* A class capturing the bounds of a buffer, to allow for run-time
1869 bounds-checking in a checked build. */
1870diff --git a/gcc/opts.c b/gcc/opts.c
1871--- a/gcc/opts.c 2020-07-22 23:35:17.708388562 -0700
1872+++ b/gcc/opts.c 2021-12-25 01:20:53.487636494 -0800
1873@@ -2439,6 +2439,14 @@ common_handle_option (struct gcc_options
1874 dc->parseable_fixits_p = value;
1875 break;
1876
1877+ case OPT_fdiagnostics_column_unit_:
1878+ dc->column_unit = (enum diagnostics_column_unit)value;
1879+ break;
1880+
1881+ case OPT_fdiagnostics_column_origin_:
1882+ dc->column_origin = value;
1883+ break;
1884+
1885 case OPT_fdiagnostics_show_cwe:
1886 dc->show_cwe = value;
1887 break;
1888@@ -2825,6 +2833,12 @@ common_handle_option (struct gcc_options
1889 check_alignment_argument (loc, arg, "functions");
1890 break;
1891
1892+ case OPT_ftabstop_:
1893+ /* It is documented that we silently ignore silly values. */
1894+ if (value >= 1 && value <= 100)
1895+ dc->tabstop = value;
1896+ break;
1897+
1898 default:
1899 /* If the flag was handled in a standard way, assume the lack of
1900 processing here is intentional. */
1901diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c
1902--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c 2020-07-22 23:35:17.908390765 -0700
1903+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c 2021-12-25 01:20:53.487636494 -0800
1904@@ -8,17 +8,22 @@
1905 We can't rely on any ordering of the keys. */
1906
1907 /* { dg-regexp "\"kind\": \"error\"" } */
1908+/* { dg-regexp "\"column-origin\": 1" } */
1909 /* { dg-regexp "\"message\": \"#error message\"" } */
1910
1911 /* { dg-regexp "\"caret\": \{" } */
1912 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-1.c\"" } */
1913 /* { dg-regexp "\"line\": 4" } */
1914 /* { dg-regexp "\"column\": 2" } */
1915+/* { dg-regexp "\"display-column\": 2" } */
1916+/* { dg-regexp "\"byte-column\": 2" } */
1917
1918 /* { dg-regexp "\"finish\": \{" } */
1919 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-1.c\"" } */
1920 /* { dg-regexp "\"line\": 4" } */
1921 /* { dg-regexp "\"column\": 6" } */
1922+/* { dg-regexp "\"display-column\": 6" } */
1923+/* { dg-regexp "\"byte-column\": 6" } */
1924
1925 /* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
1926 /* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
1927diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c
1928--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c 2020-07-22 23:35:17.908390765 -0700
1929+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c 2021-12-25 01:20:53.487636494 -0800
1930@@ -8,6 +8,7 @@
1931 We can't rely on any ordering of the keys. */
1932
1933 /* { dg-regexp "\"kind\": \"warning\"" } */
1934+/* { dg-regexp "\"column-origin\": 1" } */
1935 /* { dg-regexp "\"message\": \"#warning message\"" } */
1936 /* { dg-regexp "\"option\": \"-Wcpp\"" } */
1937 /* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
1938@@ -16,11 +17,15 @@
1939 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.c\"" } */
1940 /* { dg-regexp "\"line\": 4" } */
1941 /* { dg-regexp "\"column\": 2" } */
1942+/* { dg-regexp "\"display-column\": 2" } */
1943+/* { dg-regexp "\"byte-column\": 2" } */
1944
1945 /* { dg-regexp "\"finish\": \{" } */
1946 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.c\"" } */
1947 /* { dg-regexp "\"line\": 4" } */
1948 /* { dg-regexp "\"column\": 8" } */
1949+/* { dg-regexp "\"display-column\": 8" } */
1950+/* { dg-regexp "\"byte-column\": 8" } */
1951
1952 /* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
1953 /* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
1954diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c
1955--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c 2020-07-22 23:35:17.908390765 -0700
1956+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c 2021-12-25 01:20:53.487636494 -0800
1957@@ -8,6 +8,7 @@
1958 We can't rely on any ordering of the keys. */
1959
1960 /* { dg-regexp "\"kind\": \"error\"" } */
1961+/* { dg-regexp "\"column-origin\": 1" } */
1962 /* { dg-regexp "\"message\": \"#warning message\"" } */
1963 /* { dg-regexp "\"option\": \"-Werror=cpp\"" } */
1964 /* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
1965@@ -16,11 +17,15 @@
1966 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.c\"" } */
1967 /* { dg-regexp "\"line\": 4" } */
1968 /* { dg-regexp "\"column\": 2" } */
1969+/* { dg-regexp "\"display-column\": 2" } */
1970+/* { dg-regexp "\"byte-column\": 2" } */
1971
1972 /* { dg-regexp "\"finish\": \{" } */
1973 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.c\"" } */
1974 /* { dg-regexp "\"line\": 4" } */
1975 /* { dg-regexp "\"column\": 8" } */
1976+/* { dg-regexp "\"display-column\": 8" } */
1977+/* { dg-regexp "\"byte-column\": 8" } */
1978
1979 /* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
1980 /* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
1981diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c
1982--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c 2020-07-22 23:35:17.908390765 -0700
1983+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c 2021-12-25 01:20:53.487636494 -0800
1984@@ -24,15 +24,20 @@ int test (void)
1985 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
1986 /* { dg-regexp "\"line\": 8" } */
1987 /* { dg-regexp "\"column\": 5" } */
1988+/* { dg-regexp "\"display-column\": 5" } */
1989+/* { dg-regexp "\"byte-column\": 5" } */
1990
1991 /* { dg-regexp "\"finish\": \{" } */
1992 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
1993 /* { dg-regexp "\"line\": 8" } */
1994 /* { dg-regexp "\"column\": 10" } */
1995+/* { dg-regexp "\"display-column\": 10" } */
1996+/* { dg-regexp "\"byte-column\": 10" } */
1997
1998 /* The outer diagnostic. */
1999
2000 /* { dg-regexp "\"kind\": \"warning\"" } */
2001+/* { dg-regexp "\"column-origin\": 1" } */
2002 /* { dg-regexp "\"message\": \"this 'if' clause does not guard...\"" } */
2003 /* { dg-regexp "\"option\": \"-Wmisleading-indentation\"" } */
2004 /* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wmisleading-indentation\"" } */
2005@@ -41,11 +46,15 @@ int test (void)
2006 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
2007 /* { dg-regexp "\"line\": 6" } */
2008 /* { dg-regexp "\"column\": 3" } */
2009+/* { dg-regexp "\"display-column\": 3" } */
2010+/* { dg-regexp "\"byte-column\": 3" } */
2011
2012 /* { dg-regexp "\"finish\": \{" } */
2013 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
2014 /* { dg-regexp "\"line\": 6" } */
2015 /* { dg-regexp "\"column\": 4" } */
2016+/* { dg-regexp "\"display-column\": 4" } */
2017+/* { dg-regexp "\"byte-column\": 4" } */
2018
2019 /* More from the nested diagnostic (we can't guarantee what order the
2020 "file" keys are consumed). */
2021diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c
2022--- a/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c 2020-07-22 23:35:17.908390765 -0700
2023+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c 2021-12-25 01:20:53.487636494 -0800
2024@@ -13,6 +13,7 @@ int test (struct s *ptr)
2025 We can't rely on any ordering of the keys. */
2026
2027 /* { dg-regexp "\"kind\": \"error\"" } */
2028+/* { dg-regexp "\"column-origin\": 1" } */
2029 /* { dg-regexp "\"message\": \".*\"" } */
2030
2031 /* Verify fix-it hints. */
2032@@ -23,11 +24,15 @@ int test (struct s *ptr)
2033 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-5.c\"" } */
2034 /* { dg-regexp "\"line\": 8" } */
2035 /* { dg-regexp "\"column\": 15" } */
2036+/* { dg-regexp "\"display-column\": 15" } */
2037+/* { dg-regexp "\"byte-column\": 15" } */
2038
2039 /* { dg-regexp "\"next\": \{" } */
2040 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-5.c\"" } */
2041 /* { dg-regexp "\"line\": 8" } */
2042 /* { dg-regexp "\"column\": 21" } */
2043+/* { dg-regexp "\"display-column\": 21" } */
2044+/* { dg-regexp "\"byte-column\": 21" } */
2045
2046 /* { dg-regexp "\"fixits\": \[\[\{\}, \]*\]" } */
2047
2048@@ -35,11 +40,15 @@ int test (struct s *ptr)
2049 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-5.c\"" } */
2050 /* { dg-regexp "\"line\": 8" } */
2051 /* { dg-regexp "\"column\": 15" } */
2052+/* { dg-regexp "\"display-column\": 15" } */
2053+/* { dg-regexp "\"byte-column\": 15" } */
2054
2055 /* { dg-regexp "\"finish\": \{" } */
2056 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-5.c\"" } */
2057 /* { dg-regexp "\"line\": 8" } */
2058 /* { dg-regexp "\"column\": 20" } */
2059+/* { dg-regexp "\"display-column\": 20" } */
2060+/* { dg-regexp "\"byte-column\": 20" } */
2061
2062 /* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
2063 /* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
2064diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-1.c b/gcc/testsuite/c-c++-common/diagnostic-units-1.c
2065--- a/gcc/testsuite/c-c++-common/diagnostic-units-1.c 1969-12-31 16:00:00.000000000 -0800
2066+++ b/gcc/testsuite/c-c++-common/diagnostic-units-1.c 2021-12-25 01:20:53.487636494 -0800
2067@@ -0,0 +1,28 @@
2068+/* { dg-do compile } */
2069+/* { dg-additional-options "-fdiagnostics-column-unit=byte -fshow-column -fdiagnostics-show-caret -Wmultichar" } */
2070+
2071+/* column units: bytes (via arg)
2072+ column origin: 1 (via default)
2073+ tabstop: 8 (via default) */
2074+
2075+/* This line starts with a tab. */
2076+ int c1 = 'c1'; /* { dg-warning "11: multi-character character constant" } */
2077+/* { dg-begin-multiline-output "" }
2078+ int c1 = 'c1';
2079+ ^~~~
2080+ { dg-end-multiline-output "" } */
2081+
2082+/* This line starts with <tabstop> spaces. */
2083+ int c2 = 'c2'; /* { dg-warning "18: multi-character character constant" } */
2084+/* { dg-begin-multiline-output "" }
2085+ int c2 = 'c2';
2086+ ^~~~
2087+ { dg-end-multiline-output "" } */
2088+
2089+/* This line starts with <tabstop> spaces and has an internal tab after
2090+ a space. */
2091+ int c3 = 'c3'; /* { dg-warning "19: multi-character character constant" } */
2092+/* { dg-begin-multiline-output "" }
2093+ int c3 = 'c3';
2094+ ^~~~
2095+ { dg-end-multiline-output "" } */
2096diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-2.c b/gcc/testsuite/c-c++-common/diagnostic-units-2.c
2097--- a/gcc/testsuite/c-c++-common/diagnostic-units-2.c 1969-12-31 16:00:00.000000000 -0800
2098+++ b/gcc/testsuite/c-c++-common/diagnostic-units-2.c 2021-12-25 01:20:53.487636494 -0800
2099@@ -0,0 +1,28 @@
2100+/* { dg-do compile } */
2101+/* { dg-additional-options "-fdiagnostics-column-unit=display -fshow-column -fdiagnostics-show-caret -Wmultichar" } */
2102+
2103+/* column units: display (via arg)
2104+ column origin: 1 (via default)
2105+ tabstop: 8 (via default) */
2106+
2107+/* This line starts with a tab. */
2108+ int c1 = 'c1'; /* { dg-warning "18: multi-character character constant" } */
2109+/* { dg-begin-multiline-output "" }
2110+ int c1 = 'c1';
2111+ ^~~~
2112+ { dg-end-multiline-output "" } */
2113+
2114+/* This line starts with <tabstop> spaces. */
2115+ int c2 = 'c2'; /* { dg-warning "18: multi-character character constant" } */
2116+/* { dg-begin-multiline-output "" }
2117+ int c2 = 'c2';
2118+ ^~~~
2119+ { dg-end-multiline-output "" } */
2120+
2121+/* This line starts with <tabstop> spaces and has an internal tab after
2122+ a space. */
2123+ int c3 = 'c3'; /* { dg-warning "25: multi-character character constant" } */
2124+/* { dg-begin-multiline-output "" }
2125+ int c3 = 'c3';
2126+ ^~~~
2127+ { dg-end-multiline-output "" } */
2128diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-3.c b/gcc/testsuite/c-c++-common/diagnostic-units-3.c
2129--- a/gcc/testsuite/c-c++-common/diagnostic-units-3.c 1969-12-31 16:00:00.000000000 -0800
2130+++ b/gcc/testsuite/c-c++-common/diagnostic-units-3.c 2021-12-25 01:20:53.487636494 -0800
2131@@ -0,0 +1,28 @@
2132+/* { dg-do compile } */
2133+/* { dg-additional-options "-fdiagnostics-column-unit=byte -fshow-column -fdiagnostics-show-caret -ftabstop=200 -Wmultichar" } */
2134+
2135+/* column units: bytes (via arg)
2136+ column origin: 1 (via fallback from overly large argument)
2137+ tabstop: 8 (via default) */
2138+
2139+/* This line starts with a tab. */
2140+ int c1 = 'c1'; /* { dg-warning "11: multi-character character constant" } */
2141+/* { dg-begin-multiline-output "" }
2142+ int c1 = 'c1';
2143+ ^~~~
2144+ { dg-end-multiline-output "" } */
2145+
2146+/* This line starts with <tabstop> spaces. */
2147+ int c2 = 'c2'; /* { dg-warning "18: multi-character character constant" } */
2148+/* { dg-begin-multiline-output "" }
2149+ int c2 = 'c2';
2150+ ^~~~
2151+ { dg-end-multiline-output "" } */
2152+
2153+/* This line starts with <tabstop> spaces and has an internal tab after
2154+ a space. */
2155+ int c3 = 'c3'; /* { dg-warning "19: multi-character character constant" } */
2156+/* { dg-begin-multiline-output "" }
2157+ int c3 = 'c3';
2158+ ^~~~
2159+ { dg-end-multiline-output "" } */
2160diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-4.c b/gcc/testsuite/c-c++-common/diagnostic-units-4.c
2161--- a/gcc/testsuite/c-c++-common/diagnostic-units-4.c 1969-12-31 16:00:00.000000000 -0800
2162+++ b/gcc/testsuite/c-c++-common/diagnostic-units-4.c 2021-12-25 01:20:53.487636494 -0800
2163@@ -0,0 +1,28 @@
2164+/* { dg-do compile } */
2165+/* { dg-additional-options "-fdiagnostics-column-unit=byte -fshow-column -fdiagnostics-show-caret -fdiagnostics-column-origin=0 -Wmultichar" } */
2166+
2167+/* column units: bytes (via arg)
2168+ column origin: 0 (via arg)
2169+ tabstop: 8 (via default) */
2170+
2171+/* This line starts with a tab. */
2172+ int c1 = 'c1'; /* { dg-warning "10: multi-character character constant" } */
2173+/* { dg-begin-multiline-output "" }
2174+ int c1 = 'c1';
2175+ ^~~~
2176+ { dg-end-multiline-output "" } */
2177+
2178+/* This line starts with <tabstop> spaces. */
2179+ int c2 = 'c2'; /* { dg-warning "17: multi-character character constant" } */
2180+/* { dg-begin-multiline-output "" }
2181+ int c2 = 'c2';
2182+ ^~~~
2183+ { dg-end-multiline-output "" } */
2184+
2185+/* This line starts with <tabstop> spaces and has an internal tab after
2186+ a space. */
2187+ int c3 = 'c3'; /* { dg-warning "18: multi-character character constant" } */
2188+/* { dg-begin-multiline-output "" }
2189+ int c3 = 'c3';
2190+ ^~~~
2191+ { dg-end-multiline-output "" } */
2192diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-5.c b/gcc/testsuite/c-c++-common/diagnostic-units-5.c
2193--- a/gcc/testsuite/c-c++-common/diagnostic-units-5.c 1969-12-31 16:00:00.000000000 -0800
2194+++ b/gcc/testsuite/c-c++-common/diagnostic-units-5.c 2021-12-25 01:20:53.491636427 -0800
2195@@ -0,0 +1,28 @@
2196+/* { dg-do compile } */
2197+/* { dg-additional-options "-fdiagnostics-column-unit=display -fshow-column -fdiagnostics-show-caret -fdiagnostics-column-origin=0 -Wmultichar" } */
2198+
2199+/* column units: display (via arg)
2200+ column origin: 0 (via arg)
2201+ tabstop: 8 (via default) */
2202+
2203+/* This line starts with a tab. */
2204+ int c1 = 'c1'; /* { dg-warning "17: multi-character character constant" } */
2205+/* { dg-begin-multiline-output "" }
2206+ int c1 = 'c1';
2207+ ^~~~
2208+ { dg-end-multiline-output "" } */
2209+
2210+/* This line starts with <tabstop> spaces. */
2211+ int c2 = 'c2'; /* { dg-warning "17: multi-character character constant" } */
2212+/* { dg-begin-multiline-output "" }
2213+ int c2 = 'c2';
2214+ ^~~~
2215+ { dg-end-multiline-output "" } */
2216+
2217+/* This line starts with <tabstop> spaces and has an internal tab after
2218+ a space. */
2219+ int c3 = 'c3'; /* { dg-warning "24: multi-character character constant" } */
2220+/* { dg-begin-multiline-output "" }
2221+ int c3 = 'c3';
2222+ ^~~~
2223+ { dg-end-multiline-output "" } */
2224diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-6.c b/gcc/testsuite/c-c++-common/diagnostic-units-6.c
2225--- a/gcc/testsuite/c-c++-common/diagnostic-units-6.c 1969-12-31 16:00:00.000000000 -0800
2226+++ b/gcc/testsuite/c-c++-common/diagnostic-units-6.c 2021-12-25 01:20:53.491636427 -0800
2227@@ -0,0 +1,28 @@
2228+/* { dg-do compile } */
2229+/* { dg-additional-options "-fdiagnostics-column-unit=byte -fshow-column -fdiagnostics-show-caret -fdiagnostics-column-origin=100 -Wmultichar" } */
2230+
2231+/* column units: bytes (via arg)
2232+ column origin: 100 (via arg)
2233+ tabstop: 8 (via default) */
2234+
2235+/* This line starts with a tab. */
2236+ int c1 = 'c1'; /* { dg-warning "110: multi-character character constant" } */
2237+/* { dg-begin-multiline-output "" }
2238+ int c1 = 'c1';
2239+ ^~~~
2240+ { dg-end-multiline-output "" } */
2241+
2242+/* This line starts with <tabstop> spaces. */
2243+ int c2 = 'c2'; /* { dg-warning "117: multi-character character constant" } */
2244+/* { dg-begin-multiline-output "" }
2245+ int c2 = 'c2';
2246+ ^~~~
2247+ { dg-end-multiline-output "" } */
2248+
2249+/* This line starts with <tabstop> spaces and has an internal tab after
2250+ a space. */
2251+ int c3 = 'c3'; /* { dg-warning "118: multi-character character constant" } */
2252+/* { dg-begin-multiline-output "" }
2253+ int c3 = 'c3';
2254+ ^~~~
2255+ { dg-end-multiline-output "" } */
2256diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-7.c b/gcc/testsuite/c-c++-common/diagnostic-units-7.c
2257--- a/gcc/testsuite/c-c++-common/diagnostic-units-7.c 1969-12-31 16:00:00.000000000 -0800
2258+++ b/gcc/testsuite/c-c++-common/diagnostic-units-7.c 2021-12-25 01:20:53.491636427 -0800
2259@@ -0,0 +1,28 @@
2260+/* { dg-do compile } */
2261+/* { dg-additional-options "-fdiagnostics-column-unit=byte -fshow-column -fdiagnostics-show-caret -ftabstop=9 -Wmultichar" } */
2262+
2263+/* column units: bytes (via arg)
2264+ column origin: 1 (via default)
2265+ tabstop: 9 (via arg) */
2266+
2267+/* This line starts with a tab. */
2268+ int c1 = 'c1'; /* { dg-warning "11: multi-character character constant" } */
2269+/* { dg-begin-multiline-output "" }
2270+ int c1 = 'c1';
2271+ ^~~~
2272+ { dg-end-multiline-output "" } */
2273+
2274+/* This line starts with <tabstop> spaces. */
2275+ int c2 = 'c2'; /* { dg-warning "19: multi-character character constant" } */
2276+/* { dg-begin-multiline-output "" }
2277+ int c2 = 'c2';
2278+ ^~~~
2279+ { dg-end-multiline-output "" } */
2280+
2281+/* This line starts with <tabstop> spaces and has an internal tab after
2282+ a space. */
2283+ int c3 = 'c3'; /* { dg-warning "20: multi-character character constant" } */
2284+/* { dg-begin-multiline-output "" }
2285+ int c3 = 'c3';
2286+ ^~~~
2287+ { dg-end-multiline-output "" } */
2288diff --git a/gcc/testsuite/c-c++-common/diagnostic-units-8.c b/gcc/testsuite/c-c++-common/diagnostic-units-8.c
2289--- a/gcc/testsuite/c-c++-common/diagnostic-units-8.c 1969-12-31 16:00:00.000000000 -0800
2290+++ b/gcc/testsuite/c-c++-common/diagnostic-units-8.c 2021-12-25 01:20:53.491636427 -0800
2291@@ -0,0 +1,28 @@
2292+/* { dg-do compile } */
2293+/* { dg-additional-options "-fshow-column -fdiagnostics-show-caret -ftabstop=9 -Wmultichar" } */
2294+
2295+/* column units: display (via default)
2296+ column origin: 1 (via default)
2297+ tabstop: 9 (via arg) */
2298+
2299+/* This line starts with a tab. */
2300+ int c1 = 'c1'; /* { dg-warning "19: multi-character character constant" } */
2301+/* { dg-begin-multiline-output "" }
2302+ int c1 = 'c1';
2303+ ^~~~
2304+ { dg-end-multiline-output "" } */
2305+
2306+/* This line starts with <tabstop> spaces. */
2307+ int c2 = 'c2'; /* { dg-warning "19: multi-character character constant" } */
2308+/* { dg-begin-multiline-output "" }
2309+ int c2 = 'c2';
2310+ ^~~~
2311+ { dg-end-multiline-output "" } */
2312+
2313+/* This line starts with <tabstop> spaces and has an internal tab after
2314+ a space. */
2315+ int c3 = 'c3'; /* { dg-warning "28: multi-character character constant" } */
2316+/* { dg-begin-multiline-output "" }
2317+ int c3 = 'c3';
2318+ ^~~~
2319+ { dg-end-multiline-output "" } */
2320diff --git a/gcc/testsuite/c-c++-common/missing-close-symbol.c b/gcc/testsuite/c-c++-common/missing-close-symbol.c
2321--- a/gcc/testsuite/c-c++-common/missing-close-symbol.c 2020-07-22 23:35:17.912390810 -0700
2322+++ b/gcc/testsuite/c-c++-common/missing-close-symbol.c 2021-12-25 01:20:53.491636427 -0800
2323@@ -24,9 +24,9 @@ void test_static_assert_different_line (
2324 _Static_assert(sizeof(int) >= sizeof(char), /* { dg-message "to match this '\\('" } */
2325 "msg"; /* { dg-error "expected '\\)' before ';' token" } */
2326 /* { dg-begin-multiline-output "" }
2327- "msg";
2328- ^
2329- )
2330+ "msg";
2331+ ^
2332+ )
2333 { dg-end-multiline-output "" } */
2334 /* { dg-begin-multiline-output "" }
2335 _Static_assert(sizeof(int) >= sizeof(char),
2336diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c
2337--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c 2020-07-22 23:35:17.904390722 -0700
2338+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation-3.c 2021-12-25 01:20:53.487636494 -0800
2339@@ -36,20 +36,20 @@ int fn_6 (int a, int b, int c)
2340 /* ... */
2341 if ((err = foo (a)) != 0)
2342 goto fail;
2343- if ((err = foo (b)) != 0) /* { dg-message "2: this 'if' clause does not guard..." } */
2344+ if ((err = foo (b)) != 0) /* { dg-message "9: this 'if' clause does not guard..." } */
2345 goto fail;
2346- goto fail; /* { dg-message "3: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
2347+ goto fail; /* { dg-message "17: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
2348 if ((err = foo (c)) != 0)
2349 goto fail;
2350 /* ... */
2351
2352 /* { dg-begin-multiline-output "" }
2353- if ((err = foo (b)) != 0)
2354- ^~
2355+ if ((err = foo (b)) != 0)
2356+ ^~
2357 { dg-end-multiline-output "" } */
2358 /* { dg-begin-multiline-output "" }
2359- goto fail;
2360- ^~~~
2361+ goto fail;
2362+ ^~~~
2363 { dg-end-multiline-output "" } */
2364
2365 fail:
2366diff --git a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c
2367--- a/gcc/testsuite/c-c++-common/Wmisleading-indentation.c 2020-07-22 23:35:17.904390722 -0700
2368+++ b/gcc/testsuite/c-c++-common/Wmisleading-indentation.c 2021-12-25 01:20:53.487636494 -0800
2369@@ -65,9 +65,9 @@ int fn_6 (int a, int b, int c)
2370 /* ... */
2371 if ((err = foo (a)) != 0)
2372 goto fail;
2373- if ((err = foo (b)) != 0) /* { dg-message "2: this 'if' clause does not guard..." } */
2374+ if ((err = foo (b)) != 0) /* { dg-message "9: this 'if' clause does not guard..." } */
2375 goto fail;
2376- goto fail; /* { dg-message "3: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
2377+ goto fail; /* { dg-message "17: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
2378 if ((err = foo (c)) != 0)
2379 goto fail;
2380 /* ... */
2381@@ -178,7 +178,7 @@ void fn_16_tabs (void)
2382 while (flagA)
2383 if (flagB) /* { dg-message "7: this 'if' clause does not guard..." } */
2384 foo (0);
2385- foo (1);/* { dg-message "2: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
2386+ foo (1);/* { dg-message "9: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'" } */
2387 }
2388
2389 void fn_17_spaces (void)
2390diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-9.c b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-9.c
2391--- a/gcc/testsuite/gcc.dg/analyzer/malloc-paths-9.c 2020-07-22 23:35:18.124393144 -0700
2392+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-paths-9.c 2021-12-25 01:20:53.491636427 -0800
2393@@ -288,7 +288,7 @@ int test_3 (int x, int y)
2394 | | ~~~~~~~~~~
2395 | | |
2396 | | (4) ...to here
2397- | NN | to dereference it above
2398+ | NN | to dereference it above
2399 | NN | return *ptr;
2400 | | ~~~~
2401 | | |
2402diff --git a/gcc/testsuite/gcc.dg/bad-binary-ops.c b/gcc/testsuite/gcc.dg/bad-binary-ops.c
2403--- a/gcc/testsuite/gcc.dg/bad-binary-ops.c 2020-07-22 23:35:18.128393190 -0700
2404+++ b/gcc/testsuite/gcc.dg/bad-binary-ops.c 2021-12-25 01:20:53.491636427 -0800
2405@@ -35,10 +35,10 @@ int test_2 (void)
2406 ~~~~~~~~~~~~~~~~
2407 |
2408 struct s
2409- + some_other_function ());
2410- ^ ~~~~~~~~~~~~~~~~~~~~~~
2411- |
2412- struct t
2413+ + some_other_function ());
2414+ ^ ~~~~~~~~~~~~~~~~~~~~~~
2415+ |
2416+ struct t
2417 { dg-end-multiline-output "" } */
2418 }
2419
2420diff --git a/gcc/testsuite/gcc.dg/format/branch-1.c b/gcc/testsuite/gcc.dg/format/branch-1.c
2421--- a/gcc/testsuite/gcc.dg/format/branch-1.c 2020-07-22 23:35:18.152393454 -0700
2422+++ b/gcc/testsuite/gcc.dg/format/branch-1.c 2021-12-25 01:20:53.491636427 -0800
2423@@ -10,7 +10,7 @@ foo (long l, int nfoo)
2424 {
2425 printf ((nfoo > 1) ? "%d foos" : "%d foo", nfoo);
2426 printf ((l > 1) ? "%d foos" /* { dg-warning "23:int" "wrong type in conditional expr" } */
2427- : "%d foo", l); /* { dg-warning "16:int" "wrong type in conditional expr" } */
2428+ : "%d foo", l); /* { dg-warning "23:int" "wrong type in conditional expr" } */
2429 printf ((l > 1) ? "%ld foos" : "%d foo", l); /* { dg-warning "36:int" "wrong type in conditional expr" } */
2430 printf ((l > 1) ? "%d foos" : "%ld foo", l); /* { dg-warning "23:int" "wrong type in conditional expr" } */
2431 /* Should allow one case to have extra arguments. */
2432diff --git a/gcc/testsuite/gcc.dg/format/pr79210.c b/gcc/testsuite/gcc.dg/format/pr79210.c
2433--- a/gcc/testsuite/gcc.dg/format/pr79210.c 2020-07-22 23:35:18.152393454 -0700
2434+++ b/gcc/testsuite/gcc.dg/format/pr79210.c 2021-12-25 01:20:53.491636427 -0800
2435@@ -20,4 +20,4 @@ LPFC_VPORT_ATTR_R(peer_port_login,
2436 "Allow peer ports on the same physical port to login to each "
2437 "other.");
2438
2439-/* { dg-warning "6: format .%d. expects argument of type .int., but argument 4 has type .unsigned int. " "" { target *-*-* } .-12 } */
2440+/* { dg-warning "20: format .%d. expects argument of type .int., but argument 4 has type .unsigned int. " "" { target *-*-* } .-12 } */
2441diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c
2442--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c 2020-07-22 23:35:18.172393674 -0700
2443+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-expressions-1.c 2021-12-25 01:20:53.491636427 -0800
2444@@ -540,15 +540,15 @@ void test_builtin_types_compatible_p (un
2445 __emit_expression_range (0,
2446 f (i) + __builtin_types_compatible_p (long, int)); /* { dg-warning "range" } */
2447 /* { dg-begin-multiline-output "" }
2448- f (i) + __builtin_types_compatible_p (long, int));
2449- ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2450+ f (i) + __builtin_types_compatible_p (long, int));
2451+ ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2452 { dg-end-multiline-output "" } */
2453
2454 __emit_expression_range (0,
2455 __builtin_types_compatible_p (long, int) + f (i)); /* { dg-warning "range" } */
2456 /* { dg-begin-multiline-output "" }
2457- __builtin_types_compatible_p (long, int) + f (i));
2458- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
2459+ __builtin_types_compatible_p (long, int) + f (i));
2460+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
2461 { dg-end-multiline-output "" } */
2462 }
2463
2464@@ -671,8 +671,8 @@ void test_multiple_ordinary_maps (void)
2465 /* { dg-begin-multiline-output "" }
2466 __emit_expression_range (0, foo (0,
2467 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2468- "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
2469- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2470+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
2471+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2472 { dg-end-multiline-output "" } */
2473
2474 /* Another expression that transitions between ordinary maps; this
2475@@ -685,8 +685,8 @@ void test_multiple_ordinary_maps (void)
2476 /* { dg-begin-multiline-output "" }
2477 __emit_expression_range (0, foo (0, "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
2478 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2479- 0));
2480- ~~
2481+ 0));
2482+ ~~
2483 { dg-end-multiline-output "" } */
2484 }
2485
2486diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c
2487--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c 2020-07-22 23:35:18.172393674 -0700
2488+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c 2021-12-25 01:20:53.491636427 -0800
2489@@ -335,11 +335,11 @@ pr87652 (const char *stem, int counter)
2490 /* { dg-error "unable to read substring location: unable to read source line" "" { target c } 329 } */
2491 /* { dg-error "unable to read substring location: failed to get ordinary maps" "" { target c++ } 329 } */
2492 /* { dg-begin-multiline-output "" }
2493- __emit_string_literal_range(__FILE__":%5d: " format, \
2494+ __emit_string_literal_range(__FILE__":%5d: " format, \
2495 ^~~~~~~~
2496 { dg-end-multiline-output "" { target c } } */
2497 /* { dg-begin-multiline-output "" }
2498- __emit_string_literal_range(__FILE__":%5d: " format, \
2499+ __emit_string_literal_range(__FILE__":%5d: " format, \
2500 ^
2501 { dg-end-multiline-output "" { target c++ } } */
2502
2503diff --git a/gcc/testsuite/gcc.dg/redecl-4.c b/gcc/testsuite/gcc.dg/redecl-4.c
2504--- a/gcc/testsuite/gcc.dg/redecl-4.c 2020-07-22 23:35:18.192393895 -0700
2505+++ b/gcc/testsuite/gcc.dg/redecl-4.c 2021-12-25 01:20:53.491636427 -0800
2506@@ -15,7 +15,7 @@ f (void)
2507 /* Should get format warnings even though the built-in declaration
2508 isn't "visible". */
2509 printf (
2510- "%s", 1); /* { dg-warning "8:format" } */
2511+ "%s", 1); /* { dg-warning "15:format" } */
2512 /* The type of strcmp here should have no prototype. */
2513 if (0)
2514 strcmp (1);
2515diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
2516--- a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C 2020-07-22 23:35:17.972391472 -0700
2517+++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C 2021-12-25 01:20:53.491636427 -0800
2518@@ -33,10 +33,10 @@ int test_2 (void)
2519 ~~~~~~~~~~~~~~~~
2520 |
2521 s
2522- + some_other_function ());
2523- ^ ~~~~~~~~~~~~~~~~~~~~~~
2524- |
2525- t
2526+ + some_other_function ());
2527+ ^ ~~~~~~~~~~~~~~~~~~~~~~
2528+ |
2529+ t
2530 { dg-end-multiline-output "" } */
2531 }
2532
2533diff --git a/gcc/testsuite/g++.dg/parse/error4.C b/gcc/testsuite/g++.dg/parse/error4.C
2534--- a/gcc/testsuite/g++.dg/parse/error4.C 2020-07-22 23:35:18.012391910 -0700
2535+++ b/gcc/testsuite/g++.dg/parse/error4.C 2021-12-25 01:20:53.491636427 -0800
2536@@ -7,4 +7,4 @@ struct X {
2537 int);
2538 };
2539
2540-// { dg-error "4:'itn' has not been declared" "" { target *-*-* } 6 }
2541+// { dg-error "18:'itn' has not been declared" "" { target *-*-* } 6 }
2542diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90
2543--- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 2020-07-22 23:35:18.512397420 -0700
2544+++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 2021-12-25 01:20:53.491636427 -0800
2545@@ -8,17 +8,22 @@
2546 ! We can't rely on any ordering of the keys.
2547
2548 ! { dg-regexp "\"kind\": \"error\"" }
2549+! { dg-regexp "\"column-origin\": 1" }
2550 ! { dg-regexp "\"message\": \"#error message\"" }
2551
2552 ! { dg-regexp "\"caret\": \{" }
2553 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-1.F90\"" }
2554 ! { dg-regexp "\"line\": 4" }
2555 ! { dg-regexp "\"column\": 2" }
2556+! { dg-regexp "\"display-column\": 2" }
2557+! { dg-regexp "\"byte-column\": 2" }
2558
2559 ! { dg-regexp "\"finish\": \{" }
2560 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-1.F90\"" }
2561 ! { dg-regexp "\"line\": 4" }
2562 ! { dg-regexp "\"column\": 6" }
2563+! { dg-regexp "\"display-column\": 6" }
2564+! { dg-regexp "\"byte-column\": 6" }
2565
2566 ! { dg-regexp "\"locations\": \[\[\{\}, \]*\]" }
2567 ! { dg-regexp "\"children\": \[\[\]\[\]\]" }
2568diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90
2569--- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 2020-07-22 23:35:18.512397420 -0700
2570+++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 2021-12-25 01:20:53.491636427 -0800
2571@@ -8,6 +8,7 @@
2572 ! We can't rely on any ordering of the keys.
2573
2574 ! { dg-regexp "\"kind\": \"warning\"" }
2575+! { dg-regexp "\"column-origin\": 1" }
2576 ! { dg-regexp "\"message\": \"#warning message\"" }
2577 ! { dg-regexp "\"option\": \"-Wcpp\"" }
2578 ! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
2579@@ -16,11 +17,15 @@
2580 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.F90\"" }
2581 ! { dg-regexp "\"line\": 4" }
2582 ! { dg-regexp "\"column\": 2" }
2583+! { dg-regexp "\"display-column\": 2" }
2584+! { dg-regexp "\"byte-column\": 2" }
2585
2586 ! { dg-regexp "\"finish\": \{" }
2587 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.F90\"" }
2588 ! { dg-regexp "\"line\": 4" }
2589 ! { dg-regexp "\"column\": 8" }
2590+! { dg-regexp "\"display-column\": 8" }
2591+! { dg-regexp "\"byte-column\": 8" }
2592
2593 ! { dg-regexp "\"locations\": \[\[\{\}, \]*\]" }
2594 ! { dg-regexp "\"children\": \[\[\]\[\]\]" }
2595diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90
2596--- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 2020-07-22 23:35:18.512397420 -0700
2597+++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 2021-12-25 01:20:53.491636427 -0800
2598@@ -8,6 +8,7 @@
2599 ! We can't rely on any ordering of the keys.
2600
2601 ! { dg-regexp "\"kind\": \"error\"" }
2602+! { dg-regexp "\"column-origin\": 1" }
2603 ! { dg-regexp "\"message\": \"#warning message\"" }
2604 ! { dg-regexp "\"option\": \"-Werror=cpp\"" }
2605 ! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
2606@@ -16,11 +17,15 @@
2607 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.F90\"" }
2608 ! { dg-regexp "\"line\": 4" }
2609 ! { dg-regexp "\"column\": 2" }
2610+! { dg-regexp "\"display-column\": 2" }
2611+! { dg-regexp "\"byte-column\": 2" }
2612
2613 ! { dg-regexp "\"finish\": \{" }
2614 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.F90\"" }
2615 ! { dg-regexp "\"line\": 4" }
2616 ! { dg-regexp "\"column\": 8" }
2617+! { dg-regexp "\"display-column\": 8" }
2618+! { dg-regexp "\"byte-column\": 8" }
2619
2620 ! { dg-regexp "\"locations\": \[\[\{\}, \]*\]" }
2621 ! { dg-regexp "\"children\": \[\[\]\[\]\]" }
2622diff --git a/gcc/testsuite/go.dg/arrayclear.go b/gcc/testsuite/go.dg/arrayclear.go
2623--- a/gcc/testsuite/go.dg/arrayclear.go 2020-07-22 23:35:18.588398257 -0700
2624+++ b/gcc/testsuite/go.dg/arrayclear.go 2021-12-25 01:20:53.491636427 -0800
2625@@ -1,5 +1,8 @@
2626 // { dg-do compile }
2627 // { dg-options "-fgo-debug-optimization" }
2628+// This comment is necessary to work around a dejagnu bug. Otherwise, the
2629+// column of the second error message would equal the row of the first one, and
2630+// since the errors are also identical, dejagnu is not able to distinguish them.
2631
2632 package p
2633
2634diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C
2635--- a/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C 2020-07-22 23:35:18.048392308 -0700
2636+++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash11.C 2021-12-25 01:20:53.491636427 -0800
2637@@ -9,13 +9,13 @@ class A {
2638 int h;
2639 A() { i=10; j=20; }
2640 virtual void f1() { printf("i=%d j=%d\n",i,j); }
2641- friend virtual void f2() { printf("i=%d j=%d\n",i,j); } // { dg-error "9:virtual functions cannot be friends" }
2642+ friend virtual void f2() { printf("i=%d j=%d\n",i,j); } // { dg-error "16:virtual functions cannot be friends" }
2643 };
2644
2645 class B : public A {
2646 public:
2647 virtual void f1() { printf("i=%d j=%d\n",i,j); }// { dg-error "" } member.*// ERROR - member.*
2648- friend virtual void f2() { printf("i=%d j=%d\n",i,j); } // { dg-error "9:virtual functions cannot be friends" }
2649+ friend virtual void f2() { printf("i=%d j=%d\n",i,j); } // { dg-error "16:virtual functions cannot be friends" }
2650 // { dg-error "private" "" { target *-*-* } .-1 }
2651 };
2652
2653diff --git a/gcc/testsuite/g++.old-deja/g++.pt/overload2.C b/gcc/testsuite/g++.old-deja/g++.pt/overload2.C
2654--- a/gcc/testsuite/g++.old-deja/g++.pt/overload2.C 2020-07-22 23:35:18.072392572 -0700
2655+++ b/gcc/testsuite/g++.old-deja/g++.pt/overload2.C 2021-12-25 01:20:53.491636427 -0800
2656@@ -12,5 +12,5 @@ int
2657 main()
2658 {
2659 C<char*> c;
2660- char* p = Z(c.O); //{ dg-error "13:'Z' was not declared" } ambiguous c.O
2661+ char* p = Z(c.O); //{ dg-error "29:'Z' was not declared" } ambiguous c.O
2662 }
2663diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C
2664--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C 2020-07-22 23:35:18.076392617 -0700
2665+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C 2021-12-25 01:20:53.491636427 -0800
2666@@ -48,8 +48,8 @@ ostream& operator<<(ostream& os, Graph<V
2667
2668 // The compiler does not like this line!!!!!!
2669 typename Graph<VertexType, EdgeType>::Successor::iterator
2670- startN = G[i].second.begin(), // { dg-error "14:no match" } no index operator
2671- endN = G[i].second.end(); // { dg-error "14:no match" } no index operator
2672+ startN = G[i].second.begin(), // { dg-error "21:no match" } no index operator
2673+ endN = G[i].second.end(); // { dg-error "21:no match" } no index operator
2674
2675 while(startN != endN)
2676 {
2677diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc
2678--- a/gcc/tree-diagnostic-path.cc 2020-07-22 23:35:18.628398698 -0700
2679+++ b/gcc/tree-diagnostic-path.cc 2021-12-25 01:20:53.491636427 -0800
2680@@ -493,7 +493,7 @@ default_tree_diagnostic_path_printer (di
2681 doesn't have access to trees (for m_fndecl). */
2682
2683 json::value *
2684-default_tree_make_json_for_path (diagnostic_context *,
2685+default_tree_make_json_for_path (diagnostic_context *context,
2686 const diagnostic_path *path)
2687 {
2688 json::array *path_array = new json::array ();
2689@@ -504,7 +504,8 @@ default_tree_make_json_for_path (diagnos
2690 json::object *event_obj = new json::object ();
2691 if (event.get_location ())
2692 event_obj->set ("location",
2693- json_from_expanded_location (event.get_location ()));
2694+ json_from_expanded_location (context,
2695+ event.get_location ()));
2696 label_text event_text (event.get_desc (false));
2697 event_obj->set ("description", new json::string (event_text.m_buffer));
2698 event_text.maybe_free ();
2699diff --git a/libcpp/charset.c b/libcpp/charset.c
2700--- a/libcpp/charset.c 2020-07-22 23:35:18.712399623 -0700
2701+++ b/libcpp/charset.c 2021-12-25 01:20:53.491636427 -0800
2702@@ -2276,49 +2276,90 @@ cpp_string_location_reader::get_next ()
2703 return result;
2704 }
2705
2706-/* Helper for cpp_byte_column_to_display_column and its inverse. Given a
2707- pointer to a UTF-8-encoded character, compute its display width. *INBUFP
2708- points on entry to the start of the UTF-8 encoding of the character, and
2709- is updated to point just after the last byte of the encoding. *INBYTESLEFTP
2710- contains on entry the remaining size of the buffer into which *INBUFP
2711- points, and this is also updated accordingly. If *INBUFP does not
2712+cpp_display_width_computation::
2713+cpp_display_width_computation (const char *data, int data_length, int tabstop) :
2714+ m_begin (data),
2715+ m_next (m_begin),
2716+ m_bytes_left (data_length),
2717+ m_tabstop (tabstop),
2718+ m_display_cols (0)
2719+{
2720+ gcc_assert (m_tabstop > 0);
2721+}
2722+
2723+
2724+/* The main implementation function for class cpp_display_width_computation.
2725+ m_next points on entry to the start of the UTF-8 encoding of the next
2726+ character, and is updated to point just after the last byte of the encoding.
2727+ m_bytes_left contains on entry the remaining size of the buffer into which
2728+ m_next points, and this is also updated accordingly. If m_next does not
2729 point to a valid UTF-8-encoded sequence, then it will be treated as a single
2730- byte with display width 1. */
2731+ byte with display width 1. m_cur_display_col is the current display column,
2732+ relative to which tab stops should be expanded. Returns the display width of
2733+ the codepoint just processed. */
2734
2735-static inline int
2736-compute_next_display_width (const uchar **inbufp, size_t *inbytesleftp)
2737+int
2738+cpp_display_width_computation::process_next_codepoint ()
2739 {
2740 cppchar_t c;
2741- if (one_utf8_to_cppchar (inbufp, inbytesleftp, &c) != 0)
2742+ int next_width;
2743+
2744+ if (*m_next == '\t')
2745+ {
2746+ ++m_next;
2747+ --m_bytes_left;
2748+ next_width = m_tabstop - (m_display_cols % m_tabstop);
2749+ }
2750+ else if (one_utf8_to_cppchar ((const uchar **) &m_next, &m_bytes_left, &c)
2751+ != 0)
2752 {
2753 /* Input is not convertible to UTF-8. This could be fine, e.g. in a
2754 string literal, so don't complain. Just treat it as if it has a width
2755 of one. */
2756- ++*inbufp;
2757- --*inbytesleftp;
2758- return 1;
2759+ ++m_next;
2760+ --m_bytes_left;
2761+ next_width = 1;
2762+ }
2763+ else
2764+ {
2765+ /* one_utf8_to_cppchar() has updated m_next and m_bytes_left for us. */
2766+ next_width = cpp_wcwidth (c);
2767 }
2768
2769- /* one_utf8_to_cppchar() has updated inbufp and inbytesleftp for us. */
2770- return cpp_wcwidth (c);
2771+ m_display_cols += next_width;
2772+ return next_width;
2773+}
2774+
2775+/* Utility to advance the byte stream by the minimum amount needed to consume
2776+ N display columns. Returns the number of display columns that were
2777+ actually skipped. This could be less than N, if there was not enough data,
2778+ or more than N, if the last character to be skipped had a sufficiently large
2779+ display width. */
2780+int
2781+cpp_display_width_computation::advance_display_cols (int n)
2782+{
2783+ const int start = m_display_cols;
2784+ const int target = start + n;
2785+ while (m_display_cols < target && !done ())
2786+ process_next_codepoint ();
2787+ return m_display_cols - start;
2788 }
2789
2790 /* For the string of length DATA_LENGTH bytes that begins at DATA, compute
2791 how many display columns are occupied by the first COLUMN bytes. COLUMN
2792 may exceed DATA_LENGTH, in which case the phantom bytes at the end are
2793- treated as if they have display width 1. */
2794+ treated as if they have display width 1. Tabs are expanded to the next tab
2795+ stop, relative to the start of DATA. */
2796
2797 int
2798 cpp_byte_column_to_display_column (const char *data, int data_length,
2799- int column)
2800+ int column, int tabstop)
2801 {
2802- int display_col = 0;
2803- const uchar *udata = (const uchar *) data;
2804 const int offset = MAX (0, column - data_length);
2805- size_t inbytesleft = column - offset;
2806- while (inbytesleft)
2807- display_col += compute_next_display_width (&udata, &inbytesleft);
2808- return display_col + offset;
2809+ cpp_display_width_computation dw (data, column - offset, tabstop);
2810+ while (!dw.done ())
2811+ dw.process_next_codepoint ();
2812+ return dw.display_cols_processed () + offset;
2813 }
2814
2815 /* For the string of length DATA_LENGTH bytes that begins at DATA, compute
2816@@ -2328,14 +2369,11 @@ cpp_byte_column_to_display_column (const
2817
2818 int
2819 cpp_display_column_to_byte_column (const char *data, int data_length,
2820- int display_col)
2821+ int display_col, int tabstop)
2822 {
2823- int column = 0;
2824- const uchar *udata = (const uchar *) data;
2825- size_t inbytesleft = data_length;
2826- while (column < display_col && inbytesleft)
2827- column += compute_next_display_width (&udata, &inbytesleft);
2828- return data_length - inbytesleft + MAX (0, display_col - column);
2829+ cpp_display_width_computation dw (data, data_length, tabstop);
2830+ const int avail_display = dw.advance_display_cols (display_col);
2831+ return dw.bytes_processed () + MAX (0, display_col - avail_display);
2832 }
2833
2834 /* Our own version of wcwidth(). We don't use the actual wcwidth() in glibc,
2835diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
2836--- a/libcpp/include/cpplib.h 2020-07-22 23:35:18.712399623 -0700
2837+++ b/libcpp/include/cpplib.h 2021-12-25 01:20:53.491636427 -0800
2838@@ -312,9 +312,6 @@ enum cpp_normalize_level {
2839 carries all the options visible to the command line. */
2840 struct cpp_options
2841 {
2842- /* Characters between tab stops. */
2843- unsigned int tabstop;
2844-
2845 /* The language we're preprocessing. */
2846 enum c_lang lang;
2847
2848@@ -1322,14 +1319,43 @@ extern const char * cpp_get_userdef_suff
2849 (const cpp_token *);
2850
2851 /* In charset.c */
2852+
2853+/* A class to manage the state while converting a UTF-8 sequence to cppchar_t
2854+ and computing the display width one character at a time. */
2855+class cpp_display_width_computation {
2856+ public:
2857+ cpp_display_width_computation (const char *data, int data_length,
2858+ int tabstop);
2859+ const char *next_byte () const { return m_next; }
2860+ int bytes_processed () const { return m_next - m_begin; }
2861+ int bytes_left () const { return m_bytes_left; }
2862+ bool done () const { return !bytes_left (); }
2863+ int display_cols_processed () const { return m_display_cols; }
2864+
2865+ int process_next_codepoint ();
2866+ int advance_display_cols (int n);
2867+
2868+ private:
2869+ const char *const m_begin;
2870+ const char *m_next;
2871+ size_t m_bytes_left;
2872+ const int m_tabstop;
2873+ int m_display_cols;
2874+};
2875+
2876+/* Convenience functions that are simple use cases for class
2877+ cpp_display_width_computation. Tab characters will be expanded to spaces
2878+ as determined by TABSTOP. */
2879 int cpp_byte_column_to_display_column (const char *data, int data_length,
2880- int column);
2881-inline int cpp_display_width (const char *data, int data_length)
2882+ int column, int tabstop);
2883+inline int cpp_display_width (const char *data, int data_length,
2884+ int tabstop)
2885 {
2886- return cpp_byte_column_to_display_column (data, data_length, data_length);
2887+ return cpp_byte_column_to_display_column (data, data_length, data_length,
2888+ tabstop);
2889 }
2890 int cpp_display_column_to_byte_column (const char *data, int data_length,
2891- int display_col);
2892+ int display_col, int tabstop);
2893 int cpp_wcwidth (cppchar_t c);
2894
2895 #endif /* ! LIBCPP_CPPLIB_H */
2896diff --git a/libcpp/init.c b/libcpp/init.c
2897--- a/libcpp/init.c 2020-07-22 23:35:18.712399623 -0700
2898+++ b/libcpp/init.c 2021-12-25 01:20:53.491636427 -0800
2899@@ -190,7 +190,6 @@ cpp_create_reader (enum c_lang lang, cpp
2900 CPP_OPTION (pfile, discard_comments) = 1;
2901 CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1;
2902 CPP_OPTION (pfile, max_include_depth) = 200;
2903- CPP_OPTION (pfile, tabstop) = 8;
2904 CPP_OPTION (pfile, operator_names) = 1;
2905 CPP_OPTION (pfile, warn_trigraphs) = 2;
2906 CPP_OPTION (pfile, warn_endif_labels) = 1;