While futzing around with ctor lookup I discovered this warning about
overly-private classes.
Originally we'd allow a public copy-ctor to be sufficiently public, but
as the comment says, you need an already-constructed object for that to
work. so this implements that check -- public copy or move ctors do not
make the class sufficiently public.
I didn't implement the further suggested check of ignoring a ctor that
takes an already constructed object -- be it copy ctor or not.
applied to trunk.
nathan
--
Nathan Sidwell
2017-07-17 Nathan Sidwell <nat...@acm.org>
* class.c (maybe_warn_about_overly_private_class): Ignore public
copy ctors.
* g++.dg/warn/ctor-dtor-privacy-3.C: New.
Index: cp/class.c
===================================================================
--- cp/class.c (revision 250280)
+++ cp/class.c (working copy)
@@ -2240,10 +2240,10 @@ maybe_warn_about_overly_private_class (t
/* Warn about classes that have private constructors and no friends. */
if (TYPE_HAS_USER_CONSTRUCTOR (t)
/* Implicitly generated constructors are always public. */
- && (!CLASSTYPE_LAZY_DEFAULT_CTOR (t)
- || !CLASSTYPE_LAZY_COPY_CTOR (t)))
+ && !CLASSTYPE_LAZY_DEFAULT_CTOR (t))
{
bool nonprivate_ctor = false;
+ tree copy_or_move = NULL_TREE;
/* If a non-template class does not define a copy
constructor, one is defined for it, enabling it to avoid
@@ -2260,13 +2260,15 @@ maybe_warn_about_overly_private_class (t
else
for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t));
!nonprivate_ctor && iter; ++iter)
- /* Ideally, we wouldn't count copy constructors (or, in
- fact, any constructor that takes an argument of the class
- type as a parameter) because such things cannot be used
- to construct an instance of the class unless you already
- have one. But, for now at least, we're more
- generous. */
- if (! TREE_PRIVATE (*iter))
+ if (TREE_PRIVATE (*iter))
+ continue;
+ else if (copy_fn_p (*iter) || move_fn_p (*iter))
+ /* Ideally, we wouldn't count any constructor that takes
+ an argument of the class type as a parameter, because
+ such things cannot be used to construct an instance of
+ the class unless you already have one. */
+ copy_or_move = *iter;
+ else
nonprivate_ctor = true;
if (!nonprivate_ctor)
@@ -2274,6 +2276,10 @@ maybe_warn_about_overly_private_class (t
warning (OPT_Wctor_dtor_privacy,
"%q#T only defines private constructors and has no friends",
t);
+ if (copy_or_move)
+ inform (DECL_SOURCE_LOCATION (copy_or_move),
+ "%q#D is public, but requires an existing %q#T object",
+ copy_or_move, t);
return;
}
}
Index: testsuite/g++.dg/warn/ctor-dtor-privacy-3.C
===================================================================
--- testsuite/g++.dg/warn/ctor-dtor-privacy-3.C (revision 0)
+++ testsuite/g++.dg/warn/ctor-dtor-privacy-3.C (working copy)
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wctor-dtor-privacy" }
+
+class X // { dg-message "only defines private" }
+{
+public:
+ X (X const &); // { dg-message "requires an existing" }
+};
+
+class Y // { dg-message "only defines private" }
+{
+public:
+ Y (Y &&); // { dg-message "requires an existing" }
+};
+
+class Z
+{
+public:
+ Z (int);
+};