Hi,
On 02/12/19 19:58, Jason Merrill wrote:
On 11/29/19 8:08 AM, Paolo Carlini wrote:
Hi,
a few more rather straightforward uses for cp_expr_loc_or_input_loc.
Additionally, while working on the latter, I noticed that, compared
to say, gcc-7, lately the code we have in cp_build_addr_expr_1 to
diagnose taking the address of 'main' often doesn't work anymore,
when the argument is wrapped in a location_wrapper. The below fixes
that by using tree_strip_any_location_wrapper in the DECL_MAIN_P
check, which works fine, but I can imagine various other ways to
solve the issue...
Maybe
location_t loc = cp_expr_loc_or_input_loc (arg);
STRIP_ANY_LOCATION_WRAPPER (arg);
at the top? In general I prefer the local variable to writing
cp_expr_loc_or_input_loc in lots of places, whether or not we then
strip wrappers.
Sure. In a few circumstances I hesitated because
cp_expr_loc_or_input_loc isn't really trivial, boils down to quite a few
conditionals, and adds a bit to the complexity of simple functions when
in fact no errors nor warnings are issued. But certainly calling it at
the top is often much cleaner. I changed both the functions.
However, using STRIP_ANY_LOCATION_WRAPPER at the beginning of
cp_build_addr_expr_1 doesn't seem straightforward, causes a few
regressions (wrong location for conversion/Wwrite-strings.C; even an ICE
for cpp1z/constexpr-lambda23.C; cpp1z/decomp48.C). The function doesn't
seem trivial from this point of view, there is already a localized
tree_strip_any_location_wrapper near the end, for
processing_template_decl. I would rather further investigate that kind
of simplification in a separate patch, beyond the regression fix.
(before I would like to improve the locations for all the various kinds
of cast, quite a few changes)
Thanks, Paolo.
///////////////////////
Index: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 278911)
+++ cp/typeck.c (working copy)
@@ -6061,6 +6061,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
{
tree argtype;
tree val;
+ location_t loc;
if (!arg || error_operand_p (arg))
return error_mark_node;
@@ -6070,6 +6071,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
return error_mark_node;
argtype = lvalue_type (arg);
+ loc = cp_expr_loc_or_input_loc (arg);
gcc_assert (!(identifier_p (arg) && IDENTIFIER_ANY_OP_P (arg)));
@@ -6103,12 +6105,14 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
else if (current_class_type
&& TREE_OPERAND (arg, 0) == current_class_ref)
/* An expression like &memfn. */
- permerror (input_location, "ISO C++ forbids taking the address of
an unqualified"
+ permerror (loc,
+ "ISO C++ forbids taking the address of an unqualified"
" or parenthesized non-static member function to form"
" a pointer to member function. Say %<&%T::%D%>",
base, name);
else
- permerror (input_location, "ISO C++ forbids taking the address of a
bound member"
+ permerror (loc,
+ "ISO C++ forbids taking the address of a bound member"
" function to form a pointer to member function."
" Say %<&%T::%D%>",
base, name);
@@ -6135,7 +6139,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
if (kind == clk_none)
{
if (complain & tf_error)
- lvalue_error (cp_expr_loc_or_input_loc (arg), lv_addressof);
+ lvalue_error (loc, lv_addressof);
return error_mark_node;
}
if (strict_lvalue && (kind & (clk_rvalueref|clk_class)))
@@ -6143,8 +6147,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
if (!(complain & tf_error))
return error_mark_node;
/* Make this a permerror because we used to accept it. */
- permerror (cp_expr_loc_or_input_loc (arg),
- "taking address of rvalue");
+ permerror (loc, "taking address of rvalue");
}
}
@@ -6154,13 +6157,13 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
arg = build1 (CONVERT_EXPR, type, arg);
return arg;
}
- else if (pedantic && DECL_MAIN_P (arg))
+ else if (pedantic && DECL_MAIN_P (tree_strip_any_location_wrapper (arg)))
{
/* ARM $3.4 */
/* Apparently a lot of autoconf scripts for C++ packages do this,
so only complain if -Wpedantic. */
if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
- pedwarn (input_location, OPT_Wpedantic,
+ pedwarn (loc, OPT_Wpedantic,
"ISO C++ forbids taking address of function %<::main%>");
else if (flag_pedantic_errors)
return error_mark_node;
@@ -6218,7 +6221,8 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
if (TYPE_REF_P (TREE_TYPE (t)))
{
if (complain & tf_error)
- error ("cannot create pointer to reference member %qD", t);
+ error_at (loc,
+ "cannot create pointer to reference member %qD", t);
return error_mark_node;
}
@@ -6238,8 +6242,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
if (bitfield_p (arg))
{
if (complain & tf_error)
- error_at (cp_expr_loc_or_input_loc (arg),
- "attempt to take address of bit-field");
+ error_at (loc, "attempt to take address of bit-field");
return error_mark_node;
}
@@ -6254,8 +6257,8 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue
|| !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
{
if (complain & tf_error)
- error ("taking address of an immediate function %qD",
- stripped_arg);
+ error_at (loc, "taking address of an immediate function %qD",
+ stripped_arg);
return error_mark_node;
}
if (TREE_CODE (stripped_arg) == FUNCTION_DECL
@@ -9676,6 +9679,7 @@ check_return_expr (tree retval, bool *no_warning)
the declared type is incomplete. */
tree functype;
int fn_returns_value_p;
+ location_t loc = cp_expr_loc_or_input_loc (retval);
*no_warning = false;
@@ -9689,7 +9693,7 @@ check_return_expr (tree retval, bool *no_warning)
if (DECL_DESTRUCTOR_P (current_function_decl))
{
if (retval)
- error ("returning a value from a destructor");
+ error_at (loc, "returning a value from a destructor");
return NULL_TREE;
}
else if (DECL_CONSTRUCTOR_P (current_function_decl))
@@ -9700,7 +9704,7 @@ check_return_expr (tree retval, bool *no_warning)
error ("cannot return from a handler of a function-try-block of a
constructor");
else if (retval)
/* You can't return a value from a constructor. */
- error ("returning a value from a constructor");
+ error_at (loc, "returning a value from a constructor");
return NULL_TREE;
}
@@ -9762,11 +9766,11 @@ check_return_expr (tree retval, bool *no_warning)
else if (!same_type_p (type, functype))
{
if (LAMBDA_FUNCTION_P (current_function_decl))
- error ("inconsistent types %qT and %qT deduced for "
- "lambda return type", functype, type);
+ error_at (loc, "inconsistent types %qT and %qT deduced for "
+ "lambda return type", functype, type);
else
- error ("inconsistent deduction for auto return type: "
- "%qT and then %qT", functype, type);
+ error_at (loc, "inconsistent deduction for auto return type: "
+ "%qT and then %qT", functype, type);
}
functype = type;
}
@@ -9800,8 +9804,7 @@ check_return_expr (tree retval, bool *no_warning)
its side-effects. */
finish_expr_stmt (retval);
else if (retval != error_mark_node)
- permerror (input_location,
- "return-statement with a value, in function "
+ permerror (loc, "return-statement with a value, in function "
"returning %qT", valtype);
current_function_returns_null = 1;
@@ -9857,7 +9860,8 @@ check_return_expr (tree retval, bool *no_warning)
}
if (warn)
- warning (OPT_Weffc__, "%<operator=%> should return a reference to
%<*this%>");
+ warning_at (loc, OPT_Weffc__,
+ "%<operator=%> should return a reference to %<*this%>");
}
if (dependent_type_p (functype)
Index: testsuite/g++.dg/cpp0x/decltype3.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype3.C (revision 278911)
+++ testsuite/g++.dg/cpp0x/decltype3.C (working copy)
@@ -54,7 +54,7 @@ class B {
};
CHECK_DECLTYPE(decltype(aa.*&A::a), int&);
-decltype(aa.*&A::b) zz; // { dg-error "cannot create pointer to reference
member" "cannot" }
+decltype(aa.*&A::b) zz; // { dg-error "18:cannot create pointer to reference
member" "cannot" }
CHECK_DECLTYPE(decltype(caa.*&A::a), const int&);
Index: testsuite/g++.dg/cpp0x/decltype4.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype4.C (revision 278911)
+++ testsuite/g++.dg/cpp0x/decltype4.C (working copy)
@@ -23,7 +23,7 @@ struct A {
};
CHECK_DECLTYPE(decltype(&A::x), int A::*);
-decltype(&A::y) Ay; // { dg-error "cannot create pointer to reference
member|invalid type" }
+decltype(&A::y) Ay; // { dg-error "14:cannot create pointer to reference
member|invalid type" }
CHECK_DECLTYPE(decltype(&A::foo), int (A::*) (char));
CHECK_DECLTYPE(decltype(&A::bar), int& (A::*) () const);
Index: testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C
===================================================================
--- testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C (revision
278911)
+++ testsuite/g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C (working copy)
@@ -11,7 +11,7 @@ template <class T> int f (T t) {
if (b)
return t.fn1();
else
- return t.fn2(); // { dg-error "inconsistent types" }
+ return t.fn2(); // { dg-error "19:inconsistent types" }
}(t);
}
Index: testsuite/g++.dg/cpp2a/consteval13.C
===================================================================
--- testsuite/g++.dg/cpp2a/consteval13.C (revision 278911)
+++ testsuite/g++.dg/cpp2a/consteval13.C (working copy)
@@ -10,8 +10,8 @@ void
foo ()
{
auto qux = [] (fnptr a = quux ()) consteval { return a (); };
- constexpr auto c = qux (baz); // { dg-error "taking address of an
immediate function" }
- constexpr auto d = qux (bar); // { dg-error "taking address of an
immediate function" }
+ constexpr auto c = qux (baz); // { dg-error "28:taking address of an
immediate function" }
+ constexpr auto d = qux (bar); // { dg-error "28:taking address of an
immediate function" }
static_assert (c == 1);
static_assert (d == 42);
}
Index: testsuite/g++.dg/diagnostic/inconsistent-deduction-1.C
===================================================================
--- testsuite/g++.dg/diagnostic/inconsistent-deduction-1.C (nonexistent)
+++ testsuite/g++.dg/diagnostic/inconsistent-deduction-1.C (working copy)
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++14 } }
+
+void foo();
+
+auto bar(bool b)
+{
+ if (b)
+ return 0;
+ return foo(); // { dg-error "13:inconsistent deduction for auto return type:
.int. and then .void." }
+}
Index: testsuite/g++.dg/diagnostic/main2.C
===================================================================
--- testsuite/g++.dg/diagnostic/main2.C (nonexistent)
+++ testsuite/g++.dg/diagnostic/main2.C (working copy)
@@ -0,0 +1,12 @@
+int main ();
+
+typedef int (*fptr) ();
+
+void foo (fptr);
+
+fptr bar ()
+{
+ foo (main); // { dg-error "8:ISO C\\+\\+ forbids taking address of
function" }
+
+ return main; // { dg-error "10:ISO C\\+\\+ forbids taking address of
function" }
+}
Index: testsuite/g++.dg/diagnostic/returning-a-value-1.C
===================================================================
--- testsuite/g++.dg/diagnostic/returning-a-value-1.C (nonexistent)
+++ testsuite/g++.dg/diagnostic/returning-a-value-1.C (working copy)
@@ -0,0 +1,8 @@
+int foo();
+
+struct A
+{
+ A() { return foo(); } // { dg-error "19:returning a value" }
+ ~A() { return foo(); } // { dg-error "20:returning a value" }
+ void bar() { return foo(); } // { dg-error "26:return-statement with a
value" }
+};
Index: testsuite/g++.dg/expr/pmf-1.C
===================================================================
--- testsuite/g++.dg/expr/pmf-1.C (revision 278911)
+++ testsuite/g++.dg/expr/pmf-1.C (working copy)
@@ -13,7 +13,7 @@ struct A
void h()
{
void (A::*p)() = &A::f;
- void (A::*q)() = &(A::f); // { dg-error "parenthesized" }
+ void (A::*q)() = &(A::f); // { dg-error "27:ISO C\\+\\+ forbids
taking the address of an unqualified or parenthesized" }
foo(&g<int>); // { dg-error "cannot convert" }
}
};
Index: testsuite/g++.dg/other/ptrmem2.C
===================================================================
--- testsuite/g++.dg/other/ptrmem2.C (revision 278911)
+++ testsuite/g++.dg/other/ptrmem2.C (working copy)
@@ -19,7 +19,7 @@ template<class T> int f2(T x);
int D::Foo ()
{
- f1( &D::m); // { dg-error "cannot create pointer to ref" }
+ f1( &D::m); // { dg-error "11:cannot create pointer to ref" }
f1( &(D::m)); // ok
f2( &D::s); // ok
f2( &(D::s)); // ok
@@ -28,7 +28,7 @@ int D::Foo ()
int Foo ()
{
- f1( &D::m); // { dg-error "cannot create pointer to ref" }
+ f1( &D::m); // { dg-error "11:cannot create pointer to ref" }
f1( &(D::m)); // { dg-error "non-static" }
f2( &D::s); // ok
f2( &(D::s)); // ok
Index: testsuite/g++.dg/template/ptrmem17.C
===================================================================
--- testsuite/g++.dg/template/ptrmem17.C (revision 278911)
+++ testsuite/g++.dg/template/ptrmem17.C (working copy)
@@ -4,7 +4,7 @@ template<int> struct A
{
int& i;
A();
- ~A() { &A::i; } // { dg-error "reference" }
+ ~A() { &A::i; } // { dg-error "14:cannot create pointer to reference" }
};
A<0> a;
Index: testsuite/g++.old-deja/g++.bugs/900213_03.C
===================================================================
--- testsuite/g++.old-deja/g++.bugs/900213_03.C (revision 278911)
+++ testsuite/g++.old-deja/g++.bugs/900213_03.C (working copy)
@@ -21,7 +21,7 @@ struct0 *ptr;
void global_function_0 ()
{
- fmp = &ptr->function_member; // { dg-error "" }
+ fmp = &ptr->function_member; // { dg-error "15:ISO C\\+\\+ forbids taking
the address of a bound member function" }
//dmp = &ptr->data_member; // caught by g++, missed by cfront
}
Index: testsuite/g++.old-deja/g++.other/pmf7.C
===================================================================
--- testsuite/g++.old-deja/g++.other/pmf7.C (revision 278911)
+++ testsuite/g++.old-deja/g++.other/pmf7.C (working copy)
@@ -12,5 +12,5 @@ int main ()
{
A a;
&a.f; // { dg-error "" } overloaded
- &a.g; // { dg-error "" } can't write a pmf
like this
+ &a.g; // { dg-error "6:ISO C\\+\\+ forbids
taking the address of a bound member function" } can't write a pmf like this
}
Index: testsuite/g++.old-deja/g++.other/ptrmem7.C
===================================================================
--- testsuite/g++.old-deja/g++.other/ptrmem7.C (revision 278911)
+++ testsuite/g++.old-deja/g++.other/ptrmem7.C (working copy)
@@ -36,7 +36,7 @@ void A::foo ()
int (A::*ptr14) (int) = single; // { dg-error "cannot convert" }
int (A::*ptr20) (int) = &(A::ns); // { dg-error "pointer to member" }
- int (A::*ptr21) (int) = &(A::single); // { dg-error "pointer to member" }
+ int (A::*ptr21) (int) = &(A::single); // { dg-error "32:ISO C\\+\\+
forbids taking the address of an unqualified or parenthesized non-static member
function to form a pointer to member" }
int (*ptr31) (short) = &A::sole;
int (*ptr32) (short) = A::sole;