Hi! On Tue, Nov 20, 2018 at 04:32:26PM -0500, David Malcolm wrote: > This makes the fix-it hint wrong: after the fix-it is applied, it will > become > return color; > (which won't compile), rather than > return O::color; > which will.
Here is an updated version of the patch, which still uses the whole range of the id-expression when it is parsed as primary expression, but does so not in cp_parser_id_expression, but in cp_parser_primary_expression after all the diagnostics. Thus all the spell-checking etc. tests behave as previously, they underline only the part after the last ::, and just what uses the expression later on uses whole range. The remaining needed tweeks in the testcases are minor and look correct to me, e.g. for D::Bar the column is not at D but at B, similarly for operator"" _F the column is under _ rather than first o. The libstdc++ changes are because there are several large expressions like: something<one, two, three, four, five, six>::value and we used to diagnose on the something line (column of s) but now we warn on value line (column of v). Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2018-11-21 Jakub Jelinek <ja...@redhat.com> PR c++/87386 * parser.c (cp_parser_primary_expression): Use id_expression.get_location () instead of id_expr_token->location. Adjust the range from id_expr_token->location to id_expressio.get_finish (). (cp_parser_operator): For operator "" make a range from "" to the end of the suffix with caret at the start of the id. gcc/testsuite/ * g++.dg/diagnostic/pr87386.C: New test. * g++.dg/parse/error17.C: Adjust expected diagnostics. * g++.dg/cpp0x/pr51420.C: Likewise. * g++.dg/cpp0x/udlit-declare-neg.C: Likewise. * g++.dg/cpp0x/udlit-member-neg.C: Likewise. libstdc++-v3/ * testsuite/20_util/scoped_allocator/69293_neg.cc: Adjust expected line. * testsuite/20_util/uses_allocator/cons_neg.cc: Likewise. * testsuite/20_util/uses_allocator/69293_neg.cc: Likewise. * testsuite/experimental/propagate_const/requirements2.cc: Likewise. * testsuite/experimental/propagate_const/requirements3.cc: Likewise. * testsuite/experimental/propagate_const/requirements4.cc: Likewise. * testsuite/experimental/propagate_const/requirements5.cc: Likewise. --- gcc/cp/parser.c.jj 2018-11-21 11:35:43.698053550 +0100 +++ gcc/cp/parser.c 2018-11-21 12:23:20.701047164 +0100 @@ -5604,7 +5604,7 @@ cp_parser_primary_expression (cp_parser /*is_namespace=*/false, /*check_dependency=*/true, &ambiguous_decls, - id_expr_token->location); + id_expression.get_location ()); /* If the lookup was ambiguous, an error will already have been issued. */ if (ambiguous_decls) @@ -5675,7 +5675,7 @@ cp_parser_primary_expression (cp_parser if (parser->local_variables_forbidden_p && local_variable_p (decl)) { - error_at (id_expr_token->location, + error_at (id_expression.get_location (), "local variable %qD may not appear in this context", decl.get_value ()); return error_mark_node; @@ -5694,7 +5694,8 @@ cp_parser_primary_expression (cp_parser id_expression.get_location ())); if (error_msg) cp_parser_error (parser, error_msg); - decl.set_location (id_expr_token->location); + decl.set_location (id_expression.get_location ()); + decl.set_range (id_expr_token->location, id_expression.get_finish ()); return decl; } @@ -15051,7 +15052,7 @@ cp_literal_operator_id (const char* name static cp_expr cp_parser_operator (cp_parser* parser) { - tree id = NULL_TREE; + cp_expr id = NULL_TREE; cp_token *token; bool utf8 = false; @@ -15339,8 +15340,9 @@ cp_parser_operator (cp_parser* parser) if (id != error_mark_node) { const char *name = IDENTIFIER_POINTER (id); - id = cp_literal_operator_id (name); + *id = cp_literal_operator_id (name); } + id.set_range (start_loc, id.get_finish ()); return id; } @@ -15364,7 +15366,8 @@ cp_parser_operator (cp_parser* parser) id = error_mark_node; } - return cp_expr (id, start_loc); + id.set_location (start_loc); + return id; } /* Parse a template-declaration. --- gcc/testsuite/g++.dg/diagnostic/pr87386.C.jj 2018-11-21 14:40:58.377769686 +0100 +++ gcc/testsuite/g++.dg/diagnostic/pr87386.C 2018-11-21 14:40:19.064410070 +0100 @@ -0,0 +1,18 @@ +// PR c++/87386 +// { dg-do compile { target c++11 } } +// { dg-options "-fdiagnostics-show-caret" } + +namespace foo { + template<typename> struct test { static constexpr bool value = false; }; +} +static_assert (foo::test<int>::value, "foo"); // { dg-error "static assertion failed: foo" } +/* { dg-begin-multiline-output "" } + static_assert (foo::test<int>::value, "foo"); + ~~~~~~~~~~~~~~~~^~~~~ + { dg-end-multiline-output "" } */ + +static_assert (foo::test<int>::value && true, "bar"); // { dg-error "static assertion failed: bar" } +/* { dg-begin-multiline-output "" } + static_assert (foo::test<int>::value && true, "bar"); + ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ + { dg-end-multiline-output "" } */ --- gcc/testsuite/g++.dg/parse/error17.C.jj 2018-11-20 21:39:01.844562232 +0100 +++ gcc/testsuite/g++.dg/parse/error17.C 2018-11-21 12:15:22.117967478 +0100 @@ -6,4 +6,4 @@ template <typename T> struct B { }; struct D : B<int>, B<char> {}; -int i2 = D::Bar(2); // { dg-error "10:reference to 'Bar' is ambiguous" } +int i2 = D::Bar(2); // { dg-error "13:reference to 'Bar' is ambiguous" } --- gcc/testsuite/g++.dg/cpp0x/pr51420.C.jj 2018-11-20 21:39:02.000559703 +0100 +++ gcc/testsuite/g++.dg/cpp0x/pr51420.C 2018-11-21 12:15:22.117967478 +0100 @@ -3,6 +3,6 @@ void foo() { - float x = operator"" _F(); // { dg-error "13:'operator\"\"_F' was not declared in this scope" } + float x = operator"" _F(); // { dg-error "24:'operator\"\"_F' was not declared in this scope" } float y = 0_F; // { dg-error "unable to find numeric literal operator" } } --- gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C.jj 2018-11-20 21:39:02.049558910 +0100 +++ gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C 2018-11-21 12:15:22.117967478 +0100 @@ -7,7 +7,7 @@ public: int operator"" _Bar(char32_t); // { dg-error "7:.int Foo::operator\"\"_Bar\\(char32_t\\). must be a non-member function" } }; -int i = operator"" _Bar(U'x'); // { dg-error "9:'operator\"\"_Bar' was not declared in this scope" } +int i = operator"" _Bar(U'x'); // { dg-error "20:'operator\"\"_Bar' was not declared in this scope" } int j = U'x'_Bar; // { dg-error "unable to find character literal operator" } int --- gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C.jj 2018-11-20 21:39:01.949560531 +0100 +++ gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C 2018-11-21 12:15:22.117967478 +0100 @@ -2,14 +2,14 @@ // Check that undeclared literal operator calls and literals give appropriate errors. -int i = operator"" _Bar('x'); // { dg-error "9:'operator\"\"_Bar' was not declared in this scope" } +int i = operator"" _Bar('x'); // { dg-error "20:'operator\"\"_Bar' was not declared in this scope" } int j = 'x'_Bar; // { dg-error "unable to find character literal operator|with|argument" } -int ii = operator"" _BarCharStr("Howdy, Pardner!"); // { dg-error "10:'operator\"\"_BarCharStr' was not declared in this scope" } +int ii = operator"" _BarCharStr("Howdy, Pardner!"); // { dg-error "21:'operator\"\"_BarCharStr' was not declared in this scope" } int jj = "Howdy, Pardner!"_BarCharStr; // { dg-error "unable to find string literal operator|Possible missing length argument" } -unsigned long long iULL = operator"" _BarULL(666ULL); // { dg-error "27:'operator\"\"_BarULL' was not declared in this scope" } +unsigned long long iULL = operator"" _BarULL(666ULL); // { dg-error "38:'operator\"\"_BarULL' was not declared in this scope" } unsigned long long jULL = 666_BarULL; // { dg-error "unable to find numeric literal operator" } -long double iLD = operator"" _BarLD(666.0L); // { dg-error "19:'operator\"\"_BarLD' was not declared in this scope" } +long double iLD = operator"" _BarLD(666.0L); // { dg-error "30:'operator\"\"_BarLD' was not declared in this scope" } long double jLD = 666.0_BarLD; // { dg-error "unable to find numeric literal operator" } --- libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc.jj 2018-07-27 22:20:29.000000000 +0200 +++ libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc 2018-11-20 21:20:25.123636254 +0100 @@ -46,5 +46,5 @@ test01() scoped_alloc sa; auto p = sa.allocate(1); sa.construct(p); // this is required to be ill-formed - // { dg-error "static assertion failed" "" { target *-*-* } 94 } + // { dg-error "static assertion failed" "" { target *-*-* } 96 } } --- libstdc++-v3/testsuite/20_util/uses_allocator/cons_neg.cc.jj 2018-07-27 22:20:29.000000000 +0200 +++ libstdc++-v3/testsuite/20_util/uses_allocator/cons_neg.cc 2018-11-20 21:21:12.868864599 +0100 @@ -43,4 +43,4 @@ void test01() tuple<Type> t(allocator_arg, a, 1); } -// { dg-error "static assertion failed" "" { target *-*-* } 94 } +// { dg-error "static assertion failed" "" { target *-*-* } 96 } --- libstdc++-v3/testsuite/20_util/uses_allocator/69293_neg.cc.jj 2018-07-27 22:20:29.760136498 +0200 +++ libstdc++-v3/testsuite/20_util/uses_allocator/69293_neg.cc 2018-11-21 16:47:49.563516993 +0100 @@ -44,5 +44,5 @@ test01() { alloc_type a; std::tuple<X> t(std::allocator_arg, a); // this is required to be ill-formed - // { dg-error "static assertion failed" "" { target *-*-* } 94 } + // { dg-error "static assertion failed" "" { target *-*-* } 96 } } --- libstdc++-v3/testsuite/experimental/propagate_const/requirements3.cc.jj 2018-01-03 18:53:16.000000000 +0100 +++ libstdc++-v3/testsuite/experimental/propagate_const/requirements3.cc 2018-11-20 21:22:06.049005105 +0100 @@ -21,6 +21,6 @@ using std::experimental::propagate_const; -// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 105 } +// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 107 } propagate_const<void (*)()> test1; --- libstdc++-v3/testsuite/experimental/propagate_const/requirements4.cc.jj 2018-01-03 18:53:16.000000000 +0100 +++ libstdc++-v3/testsuite/experimental/propagate_const/requirements4.cc 2018-11-20 21:22:29.698622883 +0100 @@ -21,7 +21,7 @@ using std::experimental::propagate_const; -// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 105 } +// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 107 } // { dg-error "invalid type" "" { target *-*-* } 66 } // { dg-error "uninitialized reference member" "" { target *-*-* } 112 } --- libstdc++-v3/testsuite/experimental/propagate_const/requirements5.cc.jj 2018-01-03 18:53:16.000000000 +0100 +++ libstdc++-v3/testsuite/experimental/propagate_const/requirements5.cc 2018-11-20 21:22:45.311370550 +0100 @@ -21,6 +21,6 @@ using std::experimental::propagate_const; -// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 105 } +// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 107 } propagate_const<int[1]> test1; --- libstdc++-v3/testsuite/experimental/propagate_const/requirements2.cc.jj 2018-01-03 18:53:16.000000000 +0100 +++ libstdc++-v3/testsuite/experimental/propagate_const/requirements2.cc 2018-11-20 21:21:43.959362116 +0100 @@ -21,7 +21,7 @@ using std::experimental::propagate_const; -// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 105 } +// { dg-error "requires a class or a pointer to an object type" "" { target *-*-* } 107 } // { dg-error "not a pointer-to-object type" "" { target *-*-* } 66 } // { dg-error "forming pointer to reference type" "" { target *-*-* } 187 } // { dg-error "forming pointer to reference type" "" { target *-*-* } 213 } Jakub