On Mon, 2016-08-29 at 08:50 -0400, David Malcolm wrote:
> On Mon, 2016-08-29 at 13:44 +0200, Marek Polacek wrote:
> > On Mon, Aug 29, 2016 at 12:35:38PM +0200, Marek Polacek wrote:
> > > On Mon, Aug 29, 2016 at 11:16:25AM +0200, Andreas Schwab wrote:
> > > > On Aug 25 2016, Marek Polacek <pola...@redhat.com> wrote:
> > > > 
> > > > >       * c-c++-common/Wlogical-not-parentheses-2.c: New test.
> > > > 
> > > > FAIL: c-c++-common/Wlogical-not-parentheses-2.c  -std=gnu++11
> > > >  expected multiline pattern lines 13-17 not found: "\s*r \+=
> > > > !aaa
> > > > == bbb;.*\n             \^~\n   r \+= !aaa == bbb;.*\n       
> > > >  \^~~~\n        \(   \).*\n"
> > > > FAIL: c-c++-common/Wlogical-not-parentheses-2.c  -std=gnu++11
> > > > (test for excess errors)
> > > > Excess errors:
> > > >    r += !aaa == bbb; /* { dg-warning "logical not is only
> > > > applied" } */
> > > >              ^~
> > > >    r += !aaa == bbb; /* { dg-warning "logical not is only
> > > > applied" } */
> > > >         ^~~~
> > > 
> > > This has regressed with David's
> > > 
> > > commit 367964faf71a99ebd511dffb81075b58bff345a1
> > > Author: dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>
> > > Date:   Fri Aug 26 21:25:41 2016 +0000
> > > 
> > >     Add validation and consolidation of fix-it hints
> > >     
> > > I don't know yet what exactly went wrong here.
> > 
> > So we reject printing fix-it hint because in
> > reject_impossible_fixit:
> > 
> > 2187   if (where <= LINE_MAP_MAX_LOCATION_WITH_COLS)
> > 2188     /* WHERE is a reasonable location for a fix-it; don't
> > reject
> > it.  */
> > 2189     return false;
> > 
> > (gdb) p where
> > $1 = 2147483652
> > (gdb) p LINE_MAP_MAX_LOCATION_WITH_COLS
> > $2 = 1610612736
> > 
> > so we set m_seen_impossible_fixit.
> > 
> > David, why is that happening?
> 
> Sorry about this; I believe I did my testing of my patch against a
> tree
> that didn't yet have your change.
> 
> (gdb) p /x 2147483652
> $2 = 0x80000004
> 
> so "where", the insertion-point, is an ad-hoc location (describing a
> range), and it looks like I somehow forgot to deal with that case in
> the validation code.
> 
> I'm working on a fix.  Sorry again.

The issue affected the C++ frontend, but not the C frontend.

The root cause was that a location expressing a packed range was
passed to a make_location call as the "start" parameter.
make_location was converting the caret to a pure location (stripping
away the packed range), but wasn't doing this for the "start" parameter.
This meant that caret != start, despite them being the same
file/line/col, due to the latter containing packed range information.
This was handled by make_location by creating an ad-hoc location, and
fixit-validation doesn't yet handle ad-hoc locations for insertion
fixits, only pure locations.

The following patch fixes the issue seen in this specific case by
fixing make_location to avoid storing ranges for the endpoints of a
range, and thus avoid generating ad-hoc locations.  If a location
containing a range is passed as start or finish to make_location, it
will use the start/finish of that range respectively.

I'm working on a followup fix to make the fixit-validation code
better handle any ad-hoc locations that do make it through.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu; converts
the failures in g++.sum into passes.

Committed to trunk as r239831.

gcc/ChangeLog:
        * input.c (make_location): Call get_start and get_finish
        on the endpoints to avoid storing packed ranges or ad-hoc
        ranges in them.
        (selftest::test_make_location_nonpure_range_endpoints): New function.
        (selftest::input_c_tests): Call it.
        * input.h (get_start): New inline function.
---
 gcc/input.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 gcc/input.h |  8 ++++++++
 2 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/gcc/input.c b/gcc/input.c
index 2dcecfb..4ec218d 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -879,8 +879,8 @@ make_location (location_t caret, location_t start, 
location_t finish)
 {
   location_t pure_loc = get_pure_location (caret);
   source_range src_range;
-  src_range.m_start = start;
-  src_range.m_finish = finish;
+  src_range.m_start = get_start (start);
+  src_range.m_finish = get_finish (finish);
   location_t combined_loc = COMBINE_LOCATION_DATA (line_table,
                                                   pure_loc,
                                                   src_range,
@@ -1741,6 +1741,67 @@ test_builtins ()
   ASSERT_PRED1 (is_location_from_builtin_token, BUILTINS_LOCATION);
 }
 
+/* Regression test for make_location.
+   Ensure that we use the caret locations of the start/finish, rather
+   than storing a packed or ad-hoc range as the start/finish.  */
+
+static void
+test_make_location_nonpure_range_endpoints (const line_table_case &case_)
+{
+  /* Issue seen with testsuite/c-c++-common/Wlogical-not-parentheses-2.c
+     with C++ frontend.
+     ....................0000000001111111111222.
+     ....................1234567890123456789012.  */
+  const char *content = "     r += !aaa == bbb;\n";
+  temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
+  line_table_test ltt (case_);
+  linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+
+  const location_t c11 = linemap_position_for_column (line_table, 11);
+  const location_t c12 = linemap_position_for_column (line_table, 12);
+  const location_t c13 = linemap_position_for_column (line_table, 13);
+  const location_t c14 = linemap_position_for_column (line_table, 14);
+  const location_t c21 = linemap_position_for_column (line_table, 21);
+
+  if (c21 > LINE_MAP_MAX_LOCATION_WITH_COLS)
+    return;
+
+  /* Use column 13 for the caret location, arbitrarily, to verify that we
+     handle start != caret.  */
+  const location_t aaa = make_location (c13, c12, c14);
+  ASSERT_EQ (c13, get_pure_location (aaa));
+  ASSERT_EQ (c12, get_start (aaa));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_start (aaa)));
+  ASSERT_EQ (c14, get_finish (aaa));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_finish (aaa)));
+
+  /* Make a location using a location with a range as the start-point.  */
+  const location_t not_aaa = make_location (c11, aaa, c14);
+  ASSERT_EQ (c11, get_pure_location (not_aaa));
+  /* It should use the start location of the range, not store the range
+     itself.  */
+  ASSERT_EQ (c12, get_start (not_aaa));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_start (not_aaa)));
+  ASSERT_EQ (c14, get_finish (not_aaa));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_finish (not_aaa)));
+
+  /* Similarly, make a location with a range as the end-point.  */
+  const location_t aaa_eq_bbb = make_location (c12, c12, c21);
+  ASSERT_EQ (c12, get_pure_location (aaa_eq_bbb));
+  ASSERT_EQ (c12, get_start (aaa_eq_bbb));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_start (aaa_eq_bbb)));
+  ASSERT_EQ (c21, get_finish (aaa_eq_bbb));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_finish (aaa_eq_bbb)));
+  const location_t not_aaa_eq_bbb = make_location (c11, c12, aaa_eq_bbb);
+  /* It should use the finish location of the range, not store the range
+     itself.  */
+  ASSERT_EQ (c11, get_pure_location (not_aaa_eq_bbb));
+  ASSERT_EQ (c12, get_start (not_aaa_eq_bbb));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_start (not_aaa_eq_bbb)));
+  ASSERT_EQ (c21, get_finish (not_aaa_eq_bbb));
+  ASSERT_FALSE (IS_ADHOC_LOC (get_finish (not_aaa_eq_bbb)));
+}
+
 /* Verify reading of input files (e.g. for caret-based diagnostics).  */
 
 static void
@@ -3187,6 +3248,7 @@ input_c_tests ()
   test_should_have_column_data_p ();
   test_unknown_location ();
   test_builtins ();
+  for_each_line_table_case (test_make_location_nonpure_range_endpoints);
 
   for_each_line_table_case (test_accessing_ordinary_linemaps);
   for_each_line_table_case (test_lexer);
diff --git a/gcc/input.h b/gcc/input.h
index c99abfd..ecf8db3 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -79,6 +79,14 @@ extern location_t input_location;
 
 extern location_t get_pure_location (location_t loc);
 
+/* Get the start of any range encoded within location LOC.  */
+
+static inline location_t
+get_start (location_t loc)
+{
+  return get_range_from_loc (line_table, loc).m_start;
+}
+
 /* Get the endpoint of any range encoded within location LOC.  */
 
 static inline location_t
-- 
1.8.5.3

Reply via email to