Skip to content

Commit 7898e14

Browse files
committed
c++: Ignore access in is_implicit_lifetime trait decisions [PR122690]
I've implemented the non-aggregate part of is_implicit_lifetime paper according to the paper's comment how it can be implemented, i.e. the std::conjunction from template<typename T> struct is_implicit_lifetime : std::disjunction< std::is_scalar<T>, std::is_array<T>, std::is_aggregate<T>, std::conjunction< std::is_trivially_destructible<T>, std::disjunction< std::is_trivially_default_constructible<T>, std::is_trivially_copy_constructible<T>, std::is_trivially_move_constructible<T>>>> {}; in the paper. But as reported in PR122690, the actual wording in the paper is different from that, the https://eel.is/c++draft/class.prop#16.2 part of it: "it has at least one trivial eligible constructor and a trivial, non-deleted destructor" doesn't talk anything about accessibility of those ctors or dtors, only triviality, not being deleted and eligibility. My understanding is that GCC handles the last 2 bullets of https://eel.is/c++draft/special#6 by not adding ctors ineligible because of those into the overload at all, and for testing deleted cdtors I need to lazily declare them in case such synthetization makes them deleted. So, this patch first checks for the easy cases (where the flags on the type say the dtor is non-trivial or all the 3 special member ctors are non-trivial) and if not, lazily declares them if needed and checks if they are trivial and non-deleted. 2025-12-20 Jakub Jelinek <[email protected]> PR c++/122690 * tree.cc (implicit_lifetime_type_p): Don't test is_trivially_xible, instead try to lazily declare dtor and default, copy and move ctors if needed and check for their triviality and whether they are deleted. * g++.dg/ext/is_implicit_lifetime2.C: New test.
1 parent d91fa5f commit 7898e14

File tree

2 files changed

+108
-11
lines changed

2 files changed

+108
-11
lines changed

gcc/cp/tree.cc

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4908,18 +4908,24 @@ implicit_lifetime_type_p (tree t)
49084908
&& (!CLASSTYPE_DESTRUCTOR (t)
49094909
|| !user_provided_p (CLASSTYPE_DESTRUCTOR (t))))
49104910
return true;
4911-
if (is_trivially_xible (BIT_NOT_EXPR, t, NULL_TREE))
4911+
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
4912+
return false;
4913+
if (TYPE_HAS_COMPLEX_DFLT (t)
4914+
&& TYPE_HAS_COMPLEX_COPY_CTOR (t)
4915+
&& TYPE_HAS_COMPLEX_MOVE_CTOR (t))
4916+
return false;
4917+
if (CLASSTYPE_LAZY_DESTRUCTOR (t))
4918+
lazily_declare_fn (sfk_destructor, t);
4919+
tree fn = CLASSTYPE_DESTRUCTOR (t);
4920+
if (!fn || DECL_DELETED_FN (fn))
4921+
return false;
4922+
for (ovl_iterator iter (get_class_binding (t, complete_ctor_identifier));
4923+
iter; ++iter)
49124924
{
4913-
if (is_trivially_xible (INIT_EXPR, t, make_tree_vec (0)))
4914-
return true;
4915-
tree arg = make_tree_vec (1);
4916-
tree ct
4917-
= cp_build_qualified_type (t, (cp_type_quals (t) | TYPE_QUAL_CONST));
4918-
TREE_VEC_ELT (arg, 0) = cp_build_reference_type (ct, /*rval=*/false);
4919-
if (is_trivially_xible (INIT_EXPR, t, arg))
4920-
return true;
4921-
TREE_VEC_ELT (arg, 0) = t;
4922-
if (is_trivially_xible (INIT_EXPR, t, arg))
4925+
fn = *iter;
4926+
if ((default_ctor_p (fn) || copy_fn_p (fn) || move_fn_p (fn))
4927+
&& trivial_fn_p (fn)
4928+
&& !DECL_DELETED_FN (fn))
49234929
return true;
49244930
}
49254931
return false;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// PR c++/122690
2+
// { dg-do compile { target c++11 } }
3+
4+
class A {
5+
int i;
6+
public:
7+
A () = default;
8+
A (int i) : i(i) { }
9+
A (A const &x) : i(x.i) {}
10+
A (A &&x) : i(x.i) {}
11+
};
12+
class B {
13+
int i;
14+
protected:
15+
B () = default;
16+
public:
17+
B (int i) : i(i) { }
18+
B (B const &x) : i(x.i) {}
19+
B (B &&x) : i(x.i) {}
20+
};
21+
class C {
22+
int i;
23+
private:
24+
C () = default;
25+
public:
26+
C (int i) : i(i) { }
27+
C (C const &x) : i(x.i) {}
28+
C (C &&x) : i(x.i) {}
29+
};
30+
class D {
31+
int i;
32+
public:
33+
D (D const &) = default;
34+
D () : i(0) {}
35+
D (int i) : i(i) { }
36+
D (D &&x) : i(x.i) {}
37+
};
38+
class E {
39+
int i;
40+
protected:
41+
E (E const &) = default;
42+
public:
43+
E () : i(0) {}
44+
E (int i) : i(i) { }
45+
E (E &&x) : i(x.i) {}
46+
};
47+
class F {
48+
int i;
49+
private:
50+
F (F const &) = default;
51+
public:
52+
F () : i(0) {}
53+
F (int i) : i(i) { }
54+
F (F &&x) : i(x.i) {}
55+
};
56+
class G {
57+
int i;
58+
public:
59+
G (G &&) = default;
60+
G () : i(0) {}
61+
G (int i) : i(i) { }
62+
G (const G &x) : i(x.i) {}
63+
};
64+
class H {
65+
int i;
66+
protected:
67+
H (H &&) = default;
68+
public:
69+
H () : i(0) {}
70+
H (int i) : i(i) { }
71+
H (const H &x) : i(x.i) {}
72+
};
73+
class I {
74+
int i;
75+
private:
76+
I (I &&) = default;
77+
public:
78+
I () : i(0) {}
79+
I (int i) : i(i) { }
80+
I (const I &x) : i(x.i) {}
81+
};
82+
83+
static_assert (__builtin_is_implicit_lifetime (A), "");
84+
static_assert (__builtin_is_implicit_lifetime (B), "");
85+
static_assert (__builtin_is_implicit_lifetime (C), "");
86+
static_assert (__builtin_is_implicit_lifetime (D), "");
87+
static_assert (__builtin_is_implicit_lifetime (E), "");
88+
static_assert (__builtin_is_implicit_lifetime (F), "");
89+
static_assert (__builtin_is_implicit_lifetime (G), "");
90+
static_assert (__builtin_is_implicit_lifetime (H), "");
91+
static_assert (__builtin_is_implicit_lifetime (I), "");

0 commit comments

Comments
 (0)