Skip to content

Commit 8a7bcf9

Browse files
committed
c++: Implement __is_{nothrow_,}convertible [PR106784]
To improve compile times, the C++ library could use compiler built-ins rather than implementing std::is_convertible (and _nothrow) as class templates. This patch adds the built-ins. We already have __is_constructible and __is_assignable, and the nothrow forms of those. Microsoft (and clang, for compatibility) also provide an alias called __is_convertible_to. I did not add it, but it would be trivial to do so. I noticed that our __is_assignable doesn't implement the "Access checks are performed as if from a context unrelated to either type" requirement, therefore std::is_assignable / __is_assignable give two different results here: class S { operator int(); friend void g(); // #1 }; void g () { // #1 doesn't matter static_assert(std::is_assignable<int&, S>::value, ""); static_assert(__is_assignable(int&, S), ""); } This is not a problem if __is_assignable is not meant to be used by the users. This patch doesn't make libstdc++ use the new built-ins, but I had to rename a class otherwise its name would clash with the new built-in. PR c++/106784 gcc/c-family/ChangeLog: * c-common.cc (c_common_reswords): Add __is_convertible and __is_nothrow_convertible. * c-common.h (enum rid): Add RID_IS_CONVERTIBLE and RID_IS_NOTHROW_CONVERTIBLE. gcc/cp/ChangeLog: * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONVERTIBLE and CPTK_IS_NOTHROW_CONVERTIBLE. * cp-objcp-common.cc (names_builtin_p): Handle RID_IS_CONVERTIBLE RID_IS_NOTHROW_CONVERTIBLE. * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_CONVERTIBLE and CPTK_IS_NOTHROW_CONVERTIBLE. (is_convertible): Declare. (is_nothrow_convertible): Likewise. * cxx-pretty-print.cc (pp_cxx_trait_expression): Handle CPTK_IS_CONVERTIBLE and CPTK_IS_NOTHROW_CONVERTIBLE. * method.cc (is_convertible): New. (is_nothrow_convertible): Likewise. * parser.cc (cp_parser_primary_expression): Handle RID_IS_CONVERTIBLE and RID_IS_NOTHROW_CONVERTIBLE. (cp_parser_trait_expr): Likewise. * semantics.cc (trait_expr_value): Handle CPTK_IS_CONVERTIBLE and CPTK_IS_NOTHROW_CONVERTIBLE. (finish_trait_expr): Likewise. libstdc++-v3/ChangeLog: * include/std/type_traits: Rename __is_nothrow_convertible to __is_nothrow_convertible_lib. * testsuite/20_util/is_nothrow_convertible/value_ext.cc: Likewise. gcc/testsuite/ChangeLog: * g++.dg/ext/has-builtin-1.C: Enhance to test __is_convertible and __is_nothrow_convertible. * g++.dg/ext/is_convertible1.C: New test. * g++.dg/ext/is_convertible2.C: New test. * g++.dg/ext/is_nothrow_convertible1.C: New test. * g++.dg/ext/is_nothrow_convertible2.C: New test.
1 parent 7d4df63 commit 8a7bcf9

File tree

16 files changed

+684
-4
lines changed

16 files changed

+684
-4
lines changed

gcc/c-family/c-common.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ const struct c_common_resword c_common_reswords[] =
541541
{ "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY },
542542
{ "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY },
543543
{ "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY },
544+
{ "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY },
545+
{ "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY },
544546
{ "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY,
545547
D_CXXONLY },
546548
{ "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY,

gcc/c-family/c-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ enum rid
184184
RID_IS_UNION, RID_UNDERLYING_TYPE,
185185
RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE,
186186
RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE,
187+
RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE,
187188
RID_REF_CONSTRUCTS_FROM_TEMPORARY,
188189
RID_REF_CONVERTS_FROM_TEMPORARY,
189190

gcc/cp/constraint.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3697,6 +3697,12 @@ diagnose_trait_expr (tree expr, tree args)
36973697
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
36983698
inform (loc, " %qT does not have unique object representations", t1);
36993699
break;
3700+
case CPTK_IS_CONVERTIBLE:
3701+
inform (loc, " %qT is not convertible from %qE", t2, t1);
3702+
break;
3703+
case CPTK_IS_NOTHROW_CONVERTIBLE:
3704+
inform (loc, " %qT is not %<nothrow%> convertible from %qE", t2, t1);
3705+
break;
37003706
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
37013707
inform (loc, " %qT is not a reference that binds to a temporary "
37023708
"object of type %qT (direct-initialization)", t1, t2);

gcc/cp/cp-objcp-common.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,8 @@ names_builtin_p (const char *name)
463463
case RID_IS_NOTHROW_ASSIGNABLE:
464464
case RID_IS_NOTHROW_CONSTRUCTIBLE:
465465
case RID_UNDERLYING_TYPE:
466+
case RID_IS_CONVERTIBLE:
467+
case RID_IS_NOTHROW_CONVERTIBLE:
466468
case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
467469
case RID_REF_CONVERTS_FROM_TEMPORARY:
468470
return true;

gcc/cp/cp-tree.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,8 @@ enum cp_trait_kind
14071407
CPTK_IS_CONSTRUCTIBLE,
14081408
CPTK_IS_NOTHROW_ASSIGNABLE,
14091409
CPTK_IS_NOTHROW_CONSTRUCTIBLE,
1410+
CPTK_IS_CONVERTIBLE,
1411+
CPTK_IS_NOTHROW_CONVERTIBLE,
14101412
CPTK_REF_CONSTRUCTS_FROM_TEMPORARY,
14111413
CPTK_REF_CONVERTS_FROM_TEMPORARY
14121414
};
@@ -7116,6 +7118,8 @@ extern tree forward_parm (tree);
71167118
extern bool is_trivially_xible (enum tree_code, tree, tree);
71177119
extern bool is_nothrow_xible (enum tree_code, tree, tree);
71187120
extern bool is_xible (enum tree_code, tree, tree);
7121+
extern bool is_convertible (tree, tree);
7122+
extern bool is_nothrow_convertible (tree, tree);
71197123
extern bool ref_xes_from_temporary (tree, tree, bool);
71207124
extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error);
71217125
extern bool maybe_explain_implicit_delete (tree);

gcc/cp/cxx-pretty-print.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
26962696
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
26972697
pp_cxx_ws_string (pp, "__is_nothrow_constructible");
26982698
break;
2699+
case CPTK_IS_CONVERTIBLE:
2700+
pp_cxx_ws_string (pp, "__is_convertible");
2701+
break;
2702+
case CPTK_IS_NOTHROW_CONVERTIBLE:
2703+
pp_cxx_ws_string (pp, "__is_nothrow_convertible");
2704+
break;
26992705
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
27002706
pp_cxx_ws_string (pp, "__reference_constructs_from_temporary");
27012707
break;

gcc/cp/method.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,6 +2236,37 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
22362236
return ref_conv_binds_directly (to, val, direct_init_p).is_false ();
22372237
}
22382238

2239+
/* Return true if FROM can be converted to TO using implicit conversions,
2240+
or both FROM and TO are possibly cv-qualified void. NB: This doesn't
2241+
implement the "Access checks are performed as if from a context unrelated
2242+
to either type" restriction. */
2243+
2244+
bool
2245+
is_convertible (tree from, tree to)
2246+
{
2247+
if (VOID_TYPE_P (from) && VOID_TYPE_P (to))
2248+
return true;
2249+
tree expr = build_stub_object (from);
2250+
expr = perform_implicit_conversion (to, expr, tf_none);
2251+
if (expr == error_mark_node)
2252+
return false;
2253+
return !!expr;
2254+
}
2255+
2256+
/* Like is_convertible, but the conversion is also noexcept. */
2257+
2258+
bool
2259+
is_nothrow_convertible (tree from, tree to)
2260+
{
2261+
if (VOID_TYPE_P (from) && VOID_TYPE_P (to))
2262+
return true;
2263+
tree expr = build_stub_object (from);
2264+
expr = perform_implicit_conversion (to, expr, tf_none);
2265+
if (expr == NULL_TREE || expr == error_mark_node)
2266+
return false;
2267+
return expr_noexcept_p (expr, tf_none);
2268+
}
2269+
22392270
/* Categorize various special_function_kinds. */
22402271
#define SFK_CTOR_P(sfk) \
22412272
((sfk) >= sfk_constructor && (sfk) <= sfk_move_constructor)

gcc/cp/parser.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5922,6 +5922,8 @@ cp_parser_primary_expression (cp_parser *parser,
59225922
case RID_IS_CONSTRUCTIBLE:
59235923
case RID_IS_NOTHROW_ASSIGNABLE:
59245924
case RID_IS_NOTHROW_CONSTRUCTIBLE:
5925+
case RID_IS_CONVERTIBLE:
5926+
case RID_IS_NOTHROW_CONVERTIBLE:
59255927
case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
59265928
case RID_REF_CONVERTS_FROM_TEMPORARY:
59275929
return cp_parser_trait_expr (parser, token->keyword);
@@ -11008,6 +11010,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
1100811010
kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE;
1100911011
variadic = true;
1101011012
break;
11013+
case RID_IS_CONVERTIBLE:
11014+
kind = CPTK_IS_CONVERTIBLE;
11015+
binary = true;
11016+
break;
11017+
case RID_IS_NOTHROW_CONVERTIBLE:
11018+
kind = CPTK_IS_NOTHROW_CONVERTIBLE;
11019+
binary = true;
11020+
break;
1101111021
case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
1101211022
kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY;
1101311023
binary = true;

gcc/cp/semantics.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12044,6 +12044,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
1204412044
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
1204512045
return is_nothrow_xible (INIT_EXPR, type1, type2);
1204612046

12047+
case CPTK_IS_CONVERTIBLE:
12048+
return is_convertible (type1, type2);
12049+
12050+
case CPTK_IS_NOTHROW_CONVERTIBLE:
12051+
return is_nothrow_convertible (type1, type2);
12052+
1204712053
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
1204812054
return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
1204912055

@@ -12165,6 +12171,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
1216512171
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
1216612172
case CPTK_IS_NOTHROW_ASSIGNABLE:
1216712173
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
12174+
case CPTK_IS_CONVERTIBLE:
12175+
case CPTK_IS_NOTHROW_CONVERTIBLE:
1216812176
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
1216912177
case CPTK_REF_CONVERTS_FROM_TEMPORARY:
1217012178
if (!check_trait_type (type1)

gcc/testsuite/g++.dg/ext/has-builtin-1.C

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,9 @@
131131
#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
132132
# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
133133
#endif
134+
#if !__has_builtin (__is_convertible)
135+
# error "__has_builtin (__is_convertible) failed"
136+
#endif
137+
#if !__has_builtin (__is_nothrow_convertible)
138+
# error "__has_builtin (__is_nothrow_convertible) failed"
139+
#endif

0 commit comments

Comments
 (0)