Commit d6ef77e0 by Jason Merrill

c++: Fix implicit friend operator==.

It seems that in writing testcases for the operator<=> proposal I didn't
include any tests for implicitly declared friend operator==, and
consequently it didn't work.

2020-02-11  Jason Merrill  <jason@redhat.com>

	PR c++/93675
	* class.c (add_implicitly_declared_members): Use do_friend.
	* method.c (implicitly_declare_fn): Fix friend handling.
	(decl_remember_implicit_trigger_p): New.
	(synthesize_method): Use it.
	* decl2.c (mark_used): Use it.
parent 9a5338e5
2020-02-11 Jason Merrill <jason@redhat.com>
PR c++/93675
* class.c (add_implicitly_declared_members): Use do_friend.
* method.c (implicitly_declare_fn): Fix friend handling.
(decl_remember_implicit_trigger_p): New.
(synthesize_method): Use it.
* decl2.c (mark_used): Use it.
2020-02-11 Jason Merrill <jason@redhat.com>
PR c++/93650
PR c++/90691
* constexpr.c (maybe_constant_value): Correct earlier change.
......
......@@ -3241,6 +3241,10 @@ add_implicitly_declared_members (tree t, tree* access_decls,
{
tree eq = implicitly_declare_fn (sfk_comparison, t, false, space,
NULL_TREE);
if (DECL_FRIEND_P (space))
do_friend (NULL_TREE, DECL_NAME (eq), eq,
NULL_TREE, NO_SPECIAL, true);
else
add_method (t, eq, false);
}
......
......@@ -6801,6 +6801,7 @@ extern void after_nsdmi_defaulted_late_checks (tree);
extern bool maybe_explain_implicit_delete (tree);
extern void explain_implicit_non_constexpr (tree);
extern void deduce_inheriting_ctor (tree);
extern bool decl_remember_implicit_trigger_p (tree);
extern void synthesize_method (tree);
extern tree lazily_declare_fn (special_function_kind,
tree);
......
......@@ -5650,7 +5650,7 @@ mark_used (tree decl, tsubst_flags_t complain)
/* Remember the current location for a function we will end up
synthesizing. Then we can inform the user where it was
required in the case of error. */
if (DECL_ARTIFICIAL (decl))
if (decl_remember_implicit_trigger_p (decl))
DECL_SOURCE_LOCATION (decl) = input_location;
/* Synthesizing an implicitly defined member function will result in
......
......@@ -1463,6 +1463,22 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain)
--cp_unevaluated_operand;
}
/* True iff DECL is an implicitly-declared special member function with no real
source location, so we can use its DECL_SOURCE_LOCATION to remember where we
triggered its synthesis. */
bool
decl_remember_implicit_trigger_p (tree decl)
{
if (!DECL_ARTIFICIAL (decl))
return false;
special_function_kind sfk = special_function_p (decl);
/* Inherited constructors have the location of their using-declaration, and
operator== has the location of the corresponding operator<=>. */
return (sfk != sfk_inheriting_constructor
&& sfk != sfk_comparison);
}
/* Synthesize FNDECL, a non-static member function. */
void
......@@ -1479,7 +1495,7 @@ synthesize_method (tree fndecl)
/* Reset the source location, we might have been previously
deferred, and thus have saved where we were first needed. */
if (DECL_ARTIFICIAL (fndecl) && !DECL_INHERITED_CTOR (fndecl))
if (decl_remember_implicit_trigger_p (fndecl))
DECL_SOURCE_LOCATION (fndecl)
= DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl)));
......@@ -2717,9 +2733,15 @@ implicitly_declare_fn (special_function_kind kind, tree type,
type_set_nontrivial_flag (type, kind);
/* Create the function. */
if (friend_p)
fn_type = build_function_type (return_type, parameter_types);
else
{
tree this_type = cp_build_qualified_type (type, this_quals);
fn_type = build_method_type_directly (this_type, return_type,
parameter_types);
}
if (raises)
{
if (raises != error_mark_node)
......@@ -2794,12 +2816,19 @@ implicitly_declare_fn (special_function_kind kind, tree type,
inheriting constructor doesn't satisfy the requirements. */
constexpr_p = DECL_DECLARED_CONSTEXPR_P (inherited_ctor);
}
if (friend_p)
DECL_CONTEXT (fn) = DECL_CONTEXT (pattern_fn);
else
{
/* Add the "this" parameter. */
this_parm = build_this_parm (fn, fn_type, this_quals);
DECL_CHAIN (this_parm) = DECL_ARGUMENTS (fn);
DECL_ARGUMENTS (fn) = this_parm;
grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL);
}
DECL_IN_AGGR_P (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
DECL_DEFAULTED_FN (fn) = 1;
......
// Test with only spaceship defaulted.
// { dg-do run { target c++2a } }
#include <compare>
struct D
{
int i;
friend auto operator<=>(const D&, const D&) = default;
// friend auto operator==(const D& x, const D&) = default;
// friend auto operator!=(const D& x, const D&) = default;
// friend auto operator< (const D& x, const D&) = default;
// friend auto operator<=(const D& x, const D&) = default;
// friend auto operator> (const D& x, const D&) = default;
// friend auto operator>=(const D& x, const D&) = default;
};
#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
int main()
{
D d{42};
D d2{24};
assert (is_eq (d <=> d));
assert (is_lteq (d <=> d));
assert (is_gteq (d <=> d));
assert (is_lt (d2 <=> d));
assert (is_lteq (d2 <=> d));
assert (is_gt (d <=> d2));
assert (is_gteq (d <=> d2));
assert (d == d);
assert (!(d2 == d));
assert (!(d == d2));
assert (d != d2);
assert (!(d2 != d2));
assert (d2 < d);
assert (d2 <= d);
assert (d > d2);
assert (d >= d2);
}
// Test with only spaceship defaulted.
// { dg-do run { target c++2a } }
#include <compare>
struct D
{
int i;
friend auto operator<=>(D, D) = default;
// friend auto operator==(D, D) = default;
// friend auto operator!=(D, D) = default;
// friend auto operator< (D, D) = default;
// friend auto operator<=(D, D) = default;
// friend auto operator> (D, D) = default;
// friend auto operator>=(D, D) = default;
};
#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
int main()
{
D d{42};
D d2{24};
assert (is_eq (d <=> d));
assert (is_lteq (d <=> d));
assert (is_gteq (d <=> d));
assert (is_lt (d2 <=> d));
assert (is_lteq (d2 <=> d));
assert (is_gt (d <=> d2));
assert (is_gteq (d <=> d2));
assert (d == d);
assert (!(d2 == d));
assert (!(d == d2));
assert (d != d2);
assert (!(d2 != d2));
assert (d2 < d);
assert (d2 <= d);
assert (d > d2);
assert (d >= d2);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment