Implement P0012R1, Make exception specifications part of the type system.
gcc/cp/ * cp-tree.h (enum tsubst_flags): Add tf_fndecl_type. (flag_noexcept_type, ce_type): New. * call.c (build_conv): Add ck_fnptr. (enum conversion_kind): Change ck_tsafe to ck_fnptr. (convert_like_real): Likewise. (standard_conversion): Likewise. Allow function pointer conversions for pointers to member functions. (reference_compatible_p): Allow function pointer conversions. (direct_reference_binding): Likewise. (reference_binding): Reference-compatible is no longer a subset of reference-related. (is_subseq): Also strip ck_lvalue after next_conversion. * class.c (instantiate_type): Check fnptr_conv_p. (resolve_address_of_overloaded_function): Likewise. * cvt.c (can_convert_tx_safety): Now static. (noexcept_conv_p, fnptr_conv_p, strip_fnptr_conv): New. * decl.c (flag_noexcept_type): Define. (cxx_init_decl_processing): Set it. (bad_specifiers): Check it. (grokdeclarator) [cdk_function]: Add exception-spec to type here. * lambda.c (maybe_add_lambda_conv_op): Add exception-spec to returned pointer. * mangle.c (struct globals): Add need_cxx1z_warning. (mangle_decl): Check it. (write_exception_spec): New. (write_function_type): Call it. (canonicalize_for_substitution): Handle exception spec. (write_type): Likewise. (write_encoding): Set processing_template_decl across mangling of partially-instantiated type. * pt.c (determine_specialization): Pass tf_fndecl_type. (tsubst_decl, fn_type_unification): Likewise. (tsubst): Strip tf_fndecl_type, pass it to tsubst_exception_specification. (convert_nontype_argument_function): Handle function pointer conversion. (convert_nontype_argument): Likewise. (unify, for_each_template_parm_r): Walk into noexcept-specifier. * rtti.c (ptr_initializer): Encode noexcept. * tree.c (canonical_eh_spec): New. (build_exception_variant): Use it. * typeck.c (composite_pointer_type): Handle fnptr conversion. (comp_except_specs): Compare canonical EH specs. (structural_comptypes): Call it. gcc/c-family/ * c.opt (Wc++1z-compat): New. * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type. libstdc++-v3/ * include/bits/c++config (_GLIBCXX_NOEXCEPT_PARM) (_GLIBCXX_NOEXCEPT_QUAL): New. * include/std/type_traits (is_function): Use them. * libsubc++/new (launder): Likewise. * libsupc++/cxxabi.h (__pbase_type_info::__masks): Add __noexcept_mask. * libsupc++/pbase_type_info.cc (__do_catch): Handle function pointer conversion. libiberty/ * cp-demangle.c (is_fnqual_component_type): New. (d_encoding, d_print_comp_inner, d_print_mod_list): Use it. (FNQUAL_COMPONENT_CASE): New. (d_make_comp, has_return_type, d_print_comp_inner) (d_print_function_type): Use it. (next_is_type_qual): New. (d_cv_qualifiers, d_print_mod): Handle noexcept and throw-spec. include/ * demangle.h (enum demangle_component_type): Add DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC. From-SVN: r241944
This commit is contained in:
parent
452811eb53
commit
51dc660315
42 changed files with 801 additions and 207 deletions
|
@ -1,3 +1,8 @@
|
|||
2016-11-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* c.opt (Wc++1z-compat): New.
|
||||
* c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type.
|
||||
|
||||
2016-11-07 Martin Liska <mliska@suse.cz>
|
||||
|
||||
* c-warn.c (warn_for_unused_label): Save all labels used
|
||||
|
|
|
@ -941,6 +941,7 @@ c_cpp_builtins (cpp_reader *pfile)
|
|||
cpp_define (pfile, "__cpp_inline_variables=201606");
|
||||
cpp_define (pfile, "__cpp_aggregate_bases=201603");
|
||||
cpp_define (pfile, "__cpp_deduction_guides=201606");
|
||||
cpp_define (pfile, "__cpp_noexcept_function_type=201510");
|
||||
}
|
||||
if (flag_concepts)
|
||||
cpp_define (pfile, "__cpp_concepts=201507");
|
||||
|
|
|
@ -360,6 +360,13 @@ Wc++14-compat
|
|||
C++ ObjC++ Var(warn_cxx14_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014.
|
||||
|
||||
Wc++1z-compat
|
||||
C++ ObjC++ Var(warn_cxx1z_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2014 and (forthcoming) ISO C++ 201z(7?).
|
||||
|
||||
Wc++17-compat
|
||||
C++ ObjC++ Warning Alias(Wc++1z-compat) Undocumented
|
||||
|
||||
Wcast-qual
|
||||
C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
|
||||
Warn about casts which discard qualifiers.
|
||||
|
|
|
@ -1,5 +1,52 @@
|
|||
2016-11-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement P0012R1, Make exception specifications part of the type
|
||||
system.
|
||||
* cp-tree.h (enum tsubst_flags): Add tf_fndecl_type.
|
||||
(flag_noexcept_type, ce_type): New.
|
||||
* call.c (build_conv): Add ck_fnptr.
|
||||
(enum conversion_kind): Change ck_tsafe to ck_fnptr.
|
||||
(convert_like_real): Likewise.
|
||||
(standard_conversion): Likewise. Allow function pointer
|
||||
conversions for pointers to member functions.
|
||||
(reference_compatible_p): Allow function pointer conversions.
|
||||
(direct_reference_binding): Likewise.
|
||||
(reference_binding): Reference-compatible is no longer a subset of
|
||||
reference-related.
|
||||
(is_subseq): Also strip ck_lvalue after next_conversion.
|
||||
* class.c (instantiate_type): Check fnptr_conv_p.
|
||||
(resolve_address_of_overloaded_function): Likewise.
|
||||
* cvt.c (can_convert_tx_safety): Now static.
|
||||
(noexcept_conv_p, fnptr_conv_p, strip_fnptr_conv): New.
|
||||
* decl.c (flag_noexcept_type): Define.
|
||||
(cxx_init_decl_processing): Set it.
|
||||
(bad_specifiers): Check it.
|
||||
(grokdeclarator) [cdk_function]: Add exception-spec to type here.
|
||||
* lambda.c (maybe_add_lambda_conv_op): Add exception-spec to
|
||||
returned pointer.
|
||||
* mangle.c (struct globals): Add need_cxx1z_warning.
|
||||
(mangle_decl): Check it.
|
||||
(write_exception_spec): New.
|
||||
(write_function_type): Call it.
|
||||
(canonicalize_for_substitution): Handle exception spec.
|
||||
(write_type): Likewise.
|
||||
(write_encoding): Set processing_template_decl across mangling of
|
||||
partially-instantiated type.
|
||||
* pt.c (determine_specialization): Pass tf_fndecl_type.
|
||||
(tsubst_decl, fn_type_unification): Likewise.
|
||||
(tsubst): Strip tf_fndecl_type, pass it to
|
||||
tsubst_exception_specification.
|
||||
(convert_nontype_argument_function): Handle function pointer
|
||||
conversion.
|
||||
(convert_nontype_argument): Likewise.
|
||||
(unify, for_each_template_parm_r): Walk into noexcept-specifier.
|
||||
* rtti.c (ptr_initializer): Encode noexcept.
|
||||
* tree.c (canonical_eh_spec): New.
|
||||
(build_exception_variant): Use it.
|
||||
* typeck.c (composite_pointer_type): Handle fnptr conversion.
|
||||
(comp_except_specs): Compare canonical EH specs.
|
||||
(structural_comptypes): Call it.
|
||||
|
||||
* call.c (standard_conversion): Reorganize pointer conversions.
|
||||
* pt.c (convert_nontype_argument_function): Convert to ref here.
|
||||
(convert_nontype_argument): Not here.
|
||||
|
|
|
@ -45,7 +45,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
enum conversion_kind {
|
||||
ck_identity,
|
||||
ck_lvalue,
|
||||
ck_tsafe,
|
||||
ck_fnptr,
|
||||
ck_qual,
|
||||
ck_std,
|
||||
ck_ptr,
|
||||
|
@ -771,6 +771,7 @@ build_conv (conversion_kind code, tree type, conversion *from)
|
|||
break;
|
||||
|
||||
case ck_qual:
|
||||
case ck_fnptr:
|
||||
if (rank < cr_exact)
|
||||
rank = cr_exact;
|
||||
break;
|
||||
|
@ -1285,18 +1286,6 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
conv = build_conv (ck_ptr, from, conv);
|
||||
conv->base_p = true;
|
||||
}
|
||||
else if (tx_safe_fn_type_p (from_pointee))
|
||||
{
|
||||
/* A prvalue of type "pointer to transaction_safe function" can be
|
||||
converted to a prvalue of type "pointer to function". */
|
||||
tree unsafe = tx_unsafe_fn_variant (from_pointee);
|
||||
if (same_type_p (unsafe, to_pointee))
|
||||
{
|
||||
from_pointee = unsafe;
|
||||
from = build_pointer_type (unsafe);
|
||||
conv = build_conv (ck_tsafe, from, conv);
|
||||
}
|
||||
}
|
||||
|
||||
if (same_type_p (from, to))
|
||||
/* OK */;
|
||||
|
@ -1310,6 +1299,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
else if (expr && string_conv_p (to, expr, 0))
|
||||
/* converting from string constant to char *. */
|
||||
conv = build_conv (ck_qual, to, conv);
|
||||
else if (fnptr_conv_p (to, from))
|
||||
conv = build_conv (ck_fnptr, to, conv);
|
||||
/* Allow conversions among compatible ObjC pointer types (base
|
||||
conversions have been already handled above). */
|
||||
else if (c_dialect_objc ()
|
||||
|
@ -1332,18 +1323,29 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
tree fbase = class_of_this_parm (fromfn);
|
||||
tree tbase = class_of_this_parm (tofn);
|
||||
|
||||
if (!DERIVED_FROM_P (fbase, tbase)
|
||||
|| !same_type_p (static_fn_type (fromfn),
|
||||
static_fn_type (tofn)))
|
||||
if (!DERIVED_FROM_P (fbase, tbase))
|
||||
return NULL;
|
||||
|
||||
from = build_memfn_type (fromfn,
|
||||
tbase,
|
||||
cp_type_quals (tbase),
|
||||
type_memfn_rqual (tofn));
|
||||
from = build_ptrmemfunc_type (build_pointer_type (from));
|
||||
conv = build_conv (ck_pmem, from, conv);
|
||||
conv->base_p = true;
|
||||
tree fstat = static_fn_type (fromfn);
|
||||
tree tstat = static_fn_type (tofn);
|
||||
if (same_type_p (tstat, fstat)
|
||||
|| fnptr_conv_p (tstat, fstat))
|
||||
/* OK */;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (!same_type_p (fbase, tbase))
|
||||
{
|
||||
from = build_memfn_type (fstat,
|
||||
tbase,
|
||||
cp_type_quals (tbase),
|
||||
type_memfn_rqual (tofn));
|
||||
from = build_ptrmemfunc_type (build_pointer_type (from));
|
||||
conv = build_conv (ck_pmem, from, conv);
|
||||
conv->base_p = true;
|
||||
}
|
||||
if (fnptr_conv_p (tstat, fstat))
|
||||
conv = build_conv (ck_fnptr, to, conv);
|
||||
}
|
||||
else if (tcode == BOOLEAN_TYPE)
|
||||
{
|
||||
|
@ -1441,10 +1443,14 @@ reference_compatible_p (tree t1, tree t2)
|
|||
{
|
||||
/* [dcl.init.ref]
|
||||
|
||||
"cv1 T1" is reference compatible with "cv2 T2" if T1 is
|
||||
reference-related to T2 and cv1 is the same cv-qualification as,
|
||||
or greater cv-qualification than, cv2. */
|
||||
return (reference_related_p (t1, t2)
|
||||
"cv1 T1" is reference compatible with "cv2 T2" if
|
||||
* T1 is reference-related to T2 or
|
||||
* T2 is "noexcept function" and T1 is "function", where the
|
||||
function types are otherwise the same,
|
||||
and cv1 is the same cv-qualification as, or greater cv-qualification
|
||||
than, cv2. */
|
||||
return ((reference_related_p (t1, t2)
|
||||
|| fnptr_conv_p (t1, t2))
|
||||
&& at_least_as_qualified_p (t1, t2));
|
||||
}
|
||||
|
||||
|
@ -1478,7 +1484,7 @@ direct_reference_binding (tree type, conversion *conv)
|
|||
either an identity conversion or, if the conversion function
|
||||
returns an entity of a type that is a derived class of the
|
||||
parameter type, a derived-to-base conversion. */
|
||||
if (!same_type_ignoring_top_level_qualifiers_p (t, conv->type))
|
||||
if (is_properly_derived_from (conv->type, t))
|
||||
{
|
||||
/* Represent the derived-to-base conversion. */
|
||||
conv = build_conv (ck_base, t, conv);
|
||||
|
@ -1591,7 +1597,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
|||
[8.5.3/5 dcl.init.ref] is changed to also require direct bindings for
|
||||
const and rvalue references to rvalues of compatible class type.
|
||||
We should also do direct bindings for non-class xvalues. */
|
||||
if (related_p && gl_kind)
|
||||
if ((related_p || compatible_p) && gl_kind)
|
||||
{
|
||||
/* [dcl.init.ref]
|
||||
|
||||
|
@ -6978,9 +6984,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
|||
case ck_lvalue:
|
||||
return decay_conversion (expr, complain);
|
||||
|
||||
case ck_tsafe:
|
||||
case ck_fnptr:
|
||||
/* ??? Should the address of a transaction-safe pointer point to the TM
|
||||
clone, and this conversion look up the primary function? */
|
||||
clone, and this conversion look up the primary function? */
|
||||
return build_nop (totype, expr);
|
||||
|
||||
case ck_qual:
|
||||
|
@ -8863,10 +8869,15 @@ is_subseq (conversion *ics1, conversion *ics2)
|
|||
|
||||
ics2 = next_conversion (ics2);
|
||||
|
||||
while (ics2->kind == ck_rvalue
|
||||
|| ics2->kind == ck_lvalue)
|
||||
ics2 = next_conversion (ics2);
|
||||
|
||||
if (ics2->kind == ics1->kind
|
||||
&& same_type_p (ics2->type, ics1->type)
|
||||
&& same_type_p (next_conversion (ics2)->type,
|
||||
next_conversion (ics1)->type))
|
||||
&& (ics1->kind == ck_identity
|
||||
|| same_type_p (next_conversion (ics2)->type,
|
||||
next_conversion (ics1)->type)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8177,10 +8177,14 @@ resolve_address_of_overloaded_function (tree target_type,
|
|||
if (DECL_ANTICIPATED (fn))
|
||||
continue;
|
||||
|
||||
/* In C++17 we need the noexcept-qualifier to compare types. */
|
||||
if (flag_noexcept_type)
|
||||
maybe_instantiate_noexcept (fn);
|
||||
|
||||
/* See if there's a match. */
|
||||
tree fntype = static_fn_type (fn);
|
||||
if (same_type_p (target_fn_type, fntype)
|
||||
|| can_convert_tx_safety (target_fn_type, fntype))
|
||||
|| fnptr_conv_p (target_fn_type, fntype))
|
||||
matches = tree_cons (fn, NULL_TREE, matches);
|
||||
}
|
||||
}
|
||||
|
@ -8257,10 +8261,14 @@ resolve_address_of_overloaded_function (tree target_type,
|
|||
require_deduced_type (instantiation);
|
||||
}
|
||||
|
||||
/* In C++17 we need the noexcept-qualifier to compare types. */
|
||||
if (flag_noexcept_type)
|
||||
maybe_instantiate_noexcept (instantiation);
|
||||
|
||||
/* See if there's a match. */
|
||||
tree fntype = static_fn_type (instantiation);
|
||||
if (same_type_p (target_fn_type, fntype)
|
||||
|| can_convert_tx_safety (target_fn_type, fntype))
|
||||
|| fnptr_conv_p (target_fn_type, fntype))
|
||||
matches = tree_cons (instantiation, fn, matches);
|
||||
}
|
||||
|
||||
|
@ -8424,6 +8432,8 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t complain)
|
|||
tree fntype = non_reference (lhstype);
|
||||
if (same_type_p (fntype, TREE_TYPE (rhs)))
|
||||
return rhs;
|
||||
if (fnptr_conv_p (fntype, TREE_TYPE (rhs)))
|
||||
return rhs;
|
||||
if (flag_ms_extensions
|
||||
&& TYPE_PTRMEMFUNC_P (fntype)
|
||||
&& !TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
|
||||
|
|
|
@ -4744,6 +4744,8 @@ enum tsubst_flags {
|
|||
for calls in decltype (5.2.2/11). */
|
||||
tf_partial = 1 << 8, /* Doing initial explicit argument
|
||||
substitution in fn_type_unification. */
|
||||
tf_fndecl_type = 1 << 9, /* Substituting the type of a function
|
||||
declaration. */
|
||||
/* Convenient substitution flags combinations. */
|
||||
tf_warning_or_error = tf_warning | tf_error
|
||||
};
|
||||
|
@ -4949,6 +4951,10 @@ extern int at_eof;
|
|||
|
||||
extern bool defer_mangling_aliases;
|
||||
|
||||
/* True if noexcept is part of the type (i.e. in C++17). */
|
||||
|
||||
extern bool flag_noexcept_type;
|
||||
|
||||
/* A list of namespace-scope objects which have constructors or
|
||||
destructors which reside in the global scope. The decl is stored
|
||||
in the TREE_VALUE slot and the initializer is stored in the
|
||||
|
@ -5737,7 +5743,8 @@ extern tree type_promotes_to (tree);
|
|||
extern tree perform_qualification_conversions (tree, tree);
|
||||
extern bool tx_safe_fn_type_p (tree);
|
||||
extern tree tx_unsafe_fn_variant (tree);
|
||||
extern bool can_convert_tx_safety (tree, tree);
|
||||
extern bool fnptr_conv_p (tree, tree);
|
||||
extern tree strip_fnptr_conv (tree);
|
||||
|
||||
/* in name-lookup.c */
|
||||
extern tree pushdecl (tree);
|
||||
|
@ -6577,6 +6584,7 @@ extern tree build_overload (tree, tree);
|
|||
extern tree ovl_scope (tree);
|
||||
extern const char *cxx_printable_name (tree, int);
|
||||
extern const char *cxx_printable_name_translate (tree, int);
|
||||
extern tree canonical_eh_spec (tree);
|
||||
extern tree build_exception_variant (tree, tree);
|
||||
extern tree bind_template_template_parm (tree, tree);
|
||||
extern tree array_type_nelts_total (tree);
|
||||
|
@ -6648,7 +6656,7 @@ extern tree complete_type (tree);
|
|||
extern tree complete_type_or_else (tree, tree);
|
||||
extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t);
|
||||
extern int type_unknown_p (const_tree);
|
||||
enum { ce_derived, ce_normal, ce_exact };
|
||||
enum { ce_derived, ce_type, ce_normal, ce_exact };
|
||||
extern bool comp_except_specs (const_tree, const_tree, int);
|
||||
extern bool comptypes (tree, tree, int);
|
||||
extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
|
||||
|
|
77
gcc/cp/cvt.c
77
gcc/cp/cvt.c
|
@ -1932,9 +1932,84 @@ tx_unsafe_fn_variant (tree t)
|
|||
/* Return true iff FROM can convert to TO by a transaction-safety
|
||||
conversion. */
|
||||
|
||||
bool
|
||||
static bool
|
||||
can_convert_tx_safety (tree to, tree from)
|
||||
{
|
||||
return (flag_tm && tx_safe_fn_type_p (from)
|
||||
&& same_type_p (to, tx_unsafe_fn_variant (from)));
|
||||
}
|
||||
|
||||
/* Return true iff FROM can convert to TO by dropping noexcept. */
|
||||
|
||||
static bool
|
||||
noexcept_conv_p (tree to, tree from)
|
||||
{
|
||||
if (!flag_noexcept_type)
|
||||
return false;
|
||||
|
||||
tree t = non_reference (to);
|
||||
tree f = from;
|
||||
if (TYPE_PTRMEMFUNC_P (t)
|
||||
&& TYPE_PTRMEMFUNC_P (f))
|
||||
{
|
||||
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
|
||||
f = TYPE_PTRMEMFUNC_FN_TYPE (f);
|
||||
}
|
||||
if (TREE_CODE (t) == POINTER_TYPE
|
||||
&& TREE_CODE (f) == POINTER_TYPE)
|
||||
{
|
||||
t = TREE_TYPE (t);
|
||||
f = TREE_TYPE (f);
|
||||
}
|
||||
tree_code code = TREE_CODE (f);
|
||||
if (TREE_CODE (t) != code)
|
||||
return false;
|
||||
if (code != FUNCTION_TYPE && code != METHOD_TYPE)
|
||||
return false;
|
||||
if (!type_throw_all_p (t)
|
||||
|| type_throw_all_p (f))
|
||||
return false;
|
||||
tree v = build_exception_variant (f, NULL_TREE);
|
||||
return same_type_p (t, v);
|
||||
}
|
||||
|
||||
/* Return true iff FROM can convert to TO by a function pointer conversion. */
|
||||
|
||||
bool
|
||||
fnptr_conv_p (tree to, tree from)
|
||||
{
|
||||
tree t = non_reference (to);
|
||||
tree f = from;
|
||||
if (TYPE_PTRMEMFUNC_P (t)
|
||||
&& TYPE_PTRMEMFUNC_P (f))
|
||||
{
|
||||
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
|
||||
f = TYPE_PTRMEMFUNC_FN_TYPE (f);
|
||||
}
|
||||
if (TREE_CODE (t) == POINTER_TYPE
|
||||
&& TREE_CODE (f) == POINTER_TYPE)
|
||||
{
|
||||
t = TREE_TYPE (t);
|
||||
f = TREE_TYPE (f);
|
||||
}
|
||||
|
||||
return (noexcept_conv_p (t, f)
|
||||
|| can_convert_tx_safety (t, f));
|
||||
}
|
||||
|
||||
/* Return FN with any NOP_EXPRs that represent function pointer
|
||||
conversions stripped. */
|
||||
|
||||
tree
|
||||
strip_fnptr_conv (tree fn)
|
||||
{
|
||||
while (TREE_CODE (fn) == NOP_EXPR)
|
||||
{
|
||||
tree op = TREE_OPERAND (fn, 0);
|
||||
if (fnptr_conv_p (TREE_TYPE (fn), TREE_TYPE (op)))
|
||||
fn = op;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
|
|
@ -73,8 +73,6 @@ static int check_static_variable_definition (tree, tree);
|
|||
static void record_unknown_type (tree, const char *);
|
||||
static tree builtin_function_1 (tree, tree, bool);
|
||||
static int member_function_or_else (tree, tree, enum overload_flags);
|
||||
static void bad_specifiers (tree, enum bad_spec_place, int, int, int, int,
|
||||
int);
|
||||
static void check_for_uninitialized_const_var (tree);
|
||||
static tree local_variable_p_walkfn (tree *, int *, void *);
|
||||
static const char *tag_name (enum tag_types);
|
||||
|
@ -227,6 +225,9 @@ struct GTY((for_user)) named_label_entry {
|
|||
function, two inside the body of a function in a local class, etc.) */
|
||||
int function_depth;
|
||||
|
||||
/* Whether the exception-specifier is part of a function type (i.e. C++17). */
|
||||
bool flag_noexcept_type;
|
||||
|
||||
/* States indicating how grokdeclarator() should handle declspecs marked
|
||||
with __attribute__((deprecated)). An object declared as
|
||||
__attribute__((deprecated)) suppresses warnings of uses of other
|
||||
|
@ -4044,6 +4045,8 @@ cxx_init_decl_processing (void)
|
|||
std_node = current_namespace;
|
||||
pop_namespace ();
|
||||
|
||||
flag_noexcept_type = (cxx_dialect >= cxx1z);
|
||||
|
||||
c_common_nodes_and_builtins ();
|
||||
|
||||
integer_two_node = build_int_cst (NULL_TREE, 2);
|
||||
|
@ -7842,6 +7845,7 @@ bad_specifiers (tree object,
|
|||
if (friendp)
|
||||
error ("%q+D declared as a friend", object);
|
||||
if (raises
|
||||
&& !flag_noexcept_type
|
||||
&& (TREE_CODE (object) == TYPE_DECL
|
||||
|| (!TYPE_PTRFN_P (TREE_TYPE (object))
|
||||
&& !TYPE_REFFN_P (TREE_TYPE (object))
|
||||
|
@ -10477,6 +10481,9 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
The optional attribute-specifier-seq appertains to
|
||||
the function type. */
|
||||
decl_attributes (&type, attrs, 0);
|
||||
|
||||
if (raises)
|
||||
type = build_exception_variant (type, raises);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -1029,6 +1029,9 @@ maybe_add_lambda_conv_op (tree type)
|
|||
tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
|
||||
stattype = (cp_build_type_attribute_variant
|
||||
(stattype, TYPE_ATTRIBUTES (optype)));
|
||||
if (flag_noexcept_type
|
||||
&& TYPE_NOTHROW_P (TREE_TYPE (callop)))
|
||||
stattype = build_exception_variant (stattype, noexcept_true_spec);
|
||||
|
||||
/* First build up the conversion op. */
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ struct GTY(()) globals {
|
|||
/* True if the mangling will be different in a future version of the
|
||||
ABI. */
|
||||
bool need_abi_warning;
|
||||
|
||||
/* True if the mangling will be different in C++17 mode. */
|
||||
bool need_cxx1z_warning;
|
||||
};
|
||||
|
||||
static GTY (()) globals G;
|
||||
|
@ -344,6 +347,43 @@ dump_substitution_candidates (void)
|
|||
}
|
||||
}
|
||||
|
||||
/* <exception-spec> ::=
|
||||
Do -- non-throwing exception specification
|
||||
DO <expression> E -- computed (instantiation-dependent) noexcept
|
||||
Dw <type>* E -- throw (types) */
|
||||
|
||||
static void
|
||||
write_exception_spec (tree spec)
|
||||
{
|
||||
|
||||
if (!spec || spec == noexcept_false_spec)
|
||||
/* Nothing. */
|
||||
return;
|
||||
|
||||
if (!flag_noexcept_type)
|
||||
{
|
||||
G.need_cxx1z_warning = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (nothrow_spec_p (spec))
|
||||
write_string ("Do");
|
||||
else if (TREE_PURPOSE (spec))
|
||||
{
|
||||
gcc_assert (uses_template_parms (TREE_PURPOSE (spec)));
|
||||
write_string ("DO");
|
||||
write_expression (TREE_PURPOSE (spec));
|
||||
write_char ('E');
|
||||
}
|
||||
else
|
||||
{
|
||||
write_string ("Dw");
|
||||
for (tree t = spec; t; t = TREE_CHAIN (t))
|
||||
write_type (TREE_VALUE (t));
|
||||
write_char ('E');
|
||||
}
|
||||
}
|
||||
|
||||
/* Both decls and types can be substitution candidates, but sometimes
|
||||
they refer to the same thing. For instance, a TYPE_DECL and
|
||||
RECORD_TYPE for the same class refer to the same thing, and should
|
||||
|
@ -375,7 +415,15 @@ canonicalize_for_substitution (tree node)
|
|||
cp_type_quals (node));
|
||||
if (TREE_CODE (node) == FUNCTION_TYPE
|
||||
|| TREE_CODE (node) == METHOD_TYPE)
|
||||
node = build_ref_qualified_type (node, type_memfn_rqual (orig));
|
||||
{
|
||||
node = build_ref_qualified_type (node, type_memfn_rqual (orig));
|
||||
tree r = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (orig));
|
||||
if (flag_noexcept_type)
|
||||
node = build_exception_variant (node, r);
|
||||
else
|
||||
/* Set the warning flag if appropriate. */
|
||||
write_exception_spec (r);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
@ -777,9 +825,11 @@ write_encoding (const tree decl)
|
|||
{
|
||||
tree fn_type;
|
||||
tree d;
|
||||
bool tmpl = decl_is_template_id (decl, NULL);
|
||||
|
||||
if (decl_is_template_id (decl, NULL))
|
||||
if (tmpl)
|
||||
{
|
||||
++processing_template_decl;
|
||||
fn_type = get_mostly_instantiated_function_type (decl);
|
||||
/* FN_TYPE will not have parameter types for in-charge or
|
||||
VTT parameters. Therefore, we pass NULL_TREE to
|
||||
|
@ -796,6 +846,9 @@ write_encoding (const tree decl)
|
|||
write_bare_function_type (fn_type,
|
||||
mangle_return_type_p (decl),
|
||||
d);
|
||||
|
||||
if (tmpl)
|
||||
--processing_template_decl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2064,7 +2117,11 @@ write_type (tree type)
|
|||
type = TYPE_MAIN_VARIANT (type);
|
||||
if (TREE_CODE (type) == FUNCTION_TYPE
|
||||
|| TREE_CODE (type) == METHOD_TYPE)
|
||||
type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
|
||||
{
|
||||
type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
|
||||
type = build_exception_variant (type,
|
||||
TYPE_RAISES_EXCEPTIONS (type_orig));
|
||||
}
|
||||
|
||||
/* According to the C++ ABI, some library classes are passed the
|
||||
same as the scalar type of their single member and use the same
|
||||
|
@ -2589,6 +2646,8 @@ write_function_type (const tree type)
|
|||
write_CV_qualifiers_for_type (this_type);
|
||||
}
|
||||
|
||||
write_exception_spec (TYPE_RAISES_EXCEPTIONS (type));
|
||||
|
||||
if (tx_safe_fn_type_p (type))
|
||||
write_string ("Dx");
|
||||
|
||||
|
@ -3776,6 +3835,12 @@ mangle_decl (const tree decl)
|
|||
}
|
||||
SET_DECL_ASSEMBLER_NAME (decl, id);
|
||||
|
||||
if (G.need_cxx1z_warning)
|
||||
warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc__1z_compat,
|
||||
"mangled name for %qD will change in C++17 because the "
|
||||
"exception specification is part of a function type",
|
||||
decl);
|
||||
|
||||
if (id != DECL_NAME (decl)
|
||||
/* Don't do this for a fake symbol we aren't going to emit anyway. */
|
||||
&& TREE_CODE (decl) != TYPE_DECL
|
||||
|
|
53
gcc/cp/pt.c
53
gcc/cp/pt.c
|
@ -2216,7 +2216,7 @@ determine_specialization (tree template_id,
|
|||
continue;
|
||||
|
||||
// Then, try to form the new function type.
|
||||
insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE);
|
||||
insttype = tsubst (TREE_TYPE (fn), targs, tf_fndecl_type, NULL_TREE);
|
||||
if (insttype == error_mark_node)
|
||||
continue;
|
||||
fn_arg_types
|
||||
|
@ -5876,7 +5876,7 @@ get_underlying_template (tree tmpl)
|
|||
}
|
||||
|
||||
/* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
|
||||
must be a function or a pointer-to-function type, as specified
|
||||
must be a reference-to-function or a pointer-to-function type, as specified
|
||||
in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
|
||||
and check that the resulting function has external linkage. */
|
||||
|
||||
|
@ -5892,7 +5892,7 @@ convert_nontype_argument_function (tree type, tree expr,
|
|||
if (fn == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
fn_no_ptr = fn;
|
||||
fn_no_ptr = strip_fnptr_conv (fn);
|
||||
if (TREE_CODE (fn_no_ptr) == ADDR_EXPR)
|
||||
fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0);
|
||||
if (BASELINK_P (fn_no_ptr))
|
||||
|
@ -6672,6 +6672,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
|
|||
&& !check_valid_ptrmem_cst_expr (type, expr, complain))
|
||||
return error_mark_node;
|
||||
|
||||
/* Repeated conversion can't deal with a conversion that turns PTRMEM_CST
|
||||
into a CONSTRUCTOR, so build up a new PTRMEM_CST instead. */
|
||||
if (fnptr_conv_p (type, TREE_TYPE (expr)))
|
||||
expr = make_ptrmem_cst (type, PTRMEM_CST_MEMBER (expr));
|
||||
|
||||
/* There is no way to disable standard conversions in
|
||||
resolve_address_of_overloaded_function (called by
|
||||
instantiate_type). It is possible that the call succeeded by
|
||||
|
@ -8861,6 +8866,13 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
|
|||
want walk_tree walking into them itself. */
|
||||
*walk_subtrees = 0;
|
||||
}
|
||||
|
||||
if (flag_noexcept_type)
|
||||
{
|
||||
tree spec = TYPE_RAISES_EXCEPTIONS (t);
|
||||
if (spec)
|
||||
WALK_SUBTREE (TREE_PURPOSE (spec));
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPEOF_TYPE:
|
||||
|
@ -11932,7 +11944,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
|||
member = 0;
|
||||
ctx = DECL_CONTEXT (t);
|
||||
}
|
||||
type = tsubst (TREE_TYPE (t), args, complain, in_decl);
|
||||
type = tsubst (TREE_TYPE (t), args, complain|tf_fndecl_type, in_decl);
|
||||
if (type == error_mark_node)
|
||||
RETURN (error_mark_node);
|
||||
|
||||
|
@ -13015,6 +13027,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
}
|
||||
}
|
||||
|
||||
bool fndecl_type = (complain & tf_fndecl_type);
|
||||
complain &= ~tf_fndecl_type;
|
||||
|
||||
if (type
|
||||
&& code != TYPENAME_TYPE
|
||||
&& code != TEMPLATE_TYPE_PARM
|
||||
|
@ -13512,8 +13527,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
return error_mark_node;
|
||||
|
||||
/* Substitute the exception specification. */
|
||||
specs = tsubst_exception_specification (t, args, complain,
|
||||
in_decl, /*defer_ok*/true);
|
||||
specs = tsubst_exception_specification (t, args, complain, in_decl,
|
||||
/*defer_ok*/fndecl_type);
|
||||
if (specs == error_mark_node)
|
||||
return error_mark_node;
|
||||
if (specs)
|
||||
|
@ -17991,7 +18006,7 @@ fn_type_unification (tree fn,
|
|||
access path at this point. */
|
||||
push_deferring_access_checks (dk_deferred);
|
||||
fntype = tsubst (TREE_TYPE (fn), explicit_targs,
|
||||
complain | tf_partial, NULL_TREE);
|
||||
complain | tf_partial | tf_fndecl_type, NULL_TREE);
|
||||
pop_deferring_access_checks ();
|
||||
input_location = loc;
|
||||
processing_template_decl -= incomplete;
|
||||
|
@ -20333,9 +20348,27 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
|
|||
args[i] = TREE_VALUE (a);
|
||||
nargs = i;
|
||||
|
||||
return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
|
||||
args, nargs, 1, DEDUCE_EXACT,
|
||||
LOOKUP_NORMAL, NULL, explain_p);
|
||||
if (type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
|
||||
args, nargs, 1, DEDUCE_EXACT,
|
||||
LOOKUP_NORMAL, NULL, explain_p))
|
||||
return 1;
|
||||
|
||||
if (flag_noexcept_type)
|
||||
{
|
||||
tree pspec = TYPE_RAISES_EXCEPTIONS (parm);
|
||||
tree aspec = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (arg));
|
||||
if (pspec == NULL_TREE) pspec = noexcept_false_spec;
|
||||
if (aspec == NULL_TREE) aspec = noexcept_false_spec;
|
||||
if (TREE_PURPOSE (pspec) && TREE_PURPOSE (aspec)
|
||||
&& uses_template_parms (TREE_PURPOSE (pspec)))
|
||||
RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_PURPOSE (pspec),
|
||||
TREE_PURPOSE (aspec),
|
||||
UNIFY_ALLOW_NONE, explain_p);
|
||||
else if (nothrow_spec_p (pspec) && !nothrow_spec_p (aspec))
|
||||
return unify_type_mismatch (explain_p, parm, arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case OFFSET_TYPE:
|
||||
|
|
|
@ -985,6 +985,14 @@ ptr_initializer (tinfo_s *ti, tree target)
|
|||
flags |= 0x20;
|
||||
to = tx_unsafe_fn_variant (to);
|
||||
}
|
||||
if (flag_noexcept_type
|
||||
&& (TREE_CODE (to) == FUNCTION_TYPE
|
||||
|| TREE_CODE (to) == METHOD_TYPE)
|
||||
&& TYPE_NOTHROW_P (to))
|
||||
{
|
||||
flags |= 0x40;
|
||||
to = build_exception_variant (to, NULL_TREE);
|
||||
}
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags));
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
|
||||
|
|
|
@ -2209,6 +2209,27 @@ cxx_printable_name_translate (tree decl, int v)
|
|||
return cxx_printable_name_internal (decl, v, true);
|
||||
}
|
||||
|
||||
/* Return the canonical version of exception-specification RAISES for a C++17
|
||||
function type, for use in type comparison and building TYPE_CANONICAL. */
|
||||
|
||||
tree
|
||||
canonical_eh_spec (tree raises)
|
||||
{
|
||||
if (raises == NULL_TREE)
|
||||
return raises;
|
||||
else if (DEFERRED_NOEXCEPT_SPEC_P (raises)
|
||||
|| uses_template_parms (raises)
|
||||
|| uses_template_parms (TREE_PURPOSE (raises)))
|
||||
/* Keep a dependent or deferred exception specification. */
|
||||
return raises;
|
||||
else if (nothrow_spec_p (raises))
|
||||
/* throw() -> noexcept. */
|
||||
return noexcept_true_spec;
|
||||
else
|
||||
/* For C++17 type matching, anything else -> nothing. */
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
|
||||
listed in RAISES. */
|
||||
|
||||
|
@ -2230,6 +2251,25 @@ build_exception_variant (tree type, tree raises)
|
|||
/* Need to build a new variant. */
|
||||
v = build_variant_type_copy (type);
|
||||
TYPE_RAISES_EXCEPTIONS (v) = raises;
|
||||
|
||||
if (!flag_noexcept_type)
|
||||
/* The exception-specification is not part of the canonical type. */
|
||||
return v;
|
||||
|
||||
/* Canonicalize the exception specification. */
|
||||
tree cr = canonical_eh_spec (raises);
|
||||
|
||||
if (TYPE_STRUCTURAL_EQUALITY_P (type))
|
||||
/* Propagate structural equality. */
|
||||
SET_TYPE_STRUCTURAL_EQUALITY (v);
|
||||
else if (TYPE_CANONICAL (type) != type || cr != raises)
|
||||
/* Build the underlying canonical type, since it is different
|
||||
from TYPE. */
|
||||
TYPE_CANONICAL (v) = build_exception_variant (TYPE_CANONICAL (type), cr);
|
||||
else
|
||||
/* T is its own canonical type. */
|
||||
TYPE_CANONICAL (v) = v;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
@ -647,6 +647,14 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
|
|||
return objc_common_type (t1, t2);
|
||||
}
|
||||
|
||||
/* if T1 or T2 is "pointer to noexcept function" and the other type is
|
||||
"pointer to function", where the function types are otherwise the same,
|
||||
"pointer to function" */
|
||||
if (fnptr_conv_p (t1, t2))
|
||||
return t1;
|
||||
if (fnptr_conv_p (t2, t1))
|
||||
return t2;
|
||||
|
||||
/* [expr.eq] permits the application of a pointer conversion to
|
||||
bring the pointers to a common type. */
|
||||
if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2)
|
||||
|
@ -710,22 +718,6 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
|
|||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
else if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2)
|
||||
&& FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t1))
|
||||
&& TREE_CODE (TREE_TYPE (t2)) == TREE_CODE (TREE_TYPE (t1)))
|
||||
{
|
||||
/* ...if T1 is "pointer to transaction_safe function" and T2 is "pointer
|
||||
to function", where the function types are otherwise the same, T2, and
|
||||
vice versa.... */
|
||||
tree f1 = TREE_TYPE (t1);
|
||||
tree f2 = TREE_TYPE (t2);
|
||||
bool safe1 = tx_safe_fn_type_p (f1);
|
||||
bool safe2 = tx_safe_fn_type_p (f2);
|
||||
if (safe1 && !safe2)
|
||||
t1 = build_pointer_type (tx_unsafe_fn_variant (f1));
|
||||
else if (safe2 && !safe1)
|
||||
t2 = build_pointer_type (tx_unsafe_fn_variant (f2));
|
||||
}
|
||||
|
||||
return composite_pointer_type_r (t1, t2, operation, complain);
|
||||
}
|
||||
|
@ -1020,6 +1012,7 @@ comp_except_types (tree a, tree b, bool exact)
|
|||
|
||||
/* Return true if TYPE1 and TYPE2 are equivalent exception specifiers.
|
||||
If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5).
|
||||
If EXACT is ce_type, the C++17 type compatibility rules apply.
|
||||
If EXACT is ce_normal, the compatibility rules in 15.4/3 apply.
|
||||
If EXACT is ce_exact, the specs must be exactly the same. Exception lists
|
||||
are unordered, but we've already filtered out duplicates. Most lists will
|
||||
|
@ -1038,8 +1031,13 @@ comp_except_specs (const_tree t1, const_tree t2, int exact)
|
|||
/* First handle noexcept. */
|
||||
if (exact < ce_exact)
|
||||
{
|
||||
if (exact == ce_type
|
||||
&& (canonical_eh_spec (CONST_CAST_TREE (t1))
|
||||
== canonical_eh_spec (CONST_CAST_TREE (t2))))
|
||||
return true;
|
||||
|
||||
/* noexcept(false) is compatible with no exception-specification,
|
||||
and stricter than any spec. */
|
||||
and less strict than any spec. */
|
||||
if (t1 == noexcept_false_spec)
|
||||
return t2 == NULL_TREE || exact == ce_derived;
|
||||
/* Even a derived noexcept(false) is compatible with no
|
||||
|
@ -1222,10 +1220,17 @@ structural_comptypes (tree t1, tree t2, int strict)
|
|||
return false;
|
||||
/* Need to check this before TYPE_MAIN_VARIANT.
|
||||
FIXME function qualifiers should really change the main variant. */
|
||||
if ((TREE_CODE (t1) == FUNCTION_TYPE
|
||||
|| TREE_CODE (t1) == METHOD_TYPE)
|
||||
&& type_memfn_rqual (t1) != type_memfn_rqual (t2))
|
||||
return false;
|
||||
if (TREE_CODE (t1) == FUNCTION_TYPE
|
||||
|| TREE_CODE (t1) == METHOD_TYPE)
|
||||
{
|
||||
if (type_memfn_rqual (t1) != type_memfn_rqual (t2))
|
||||
return false;
|
||||
if (flag_noexcept_type
|
||||
&& !comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
|
||||
TYPE_RAISES_EXCEPTIONS (t2),
|
||||
ce_type))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Allow for two different type nodes which have essentially the same
|
||||
definition. Note that we already checked for equality of the type
|
||||
|
|
|
@ -5574,6 +5574,11 @@ enabled by @option{-Wall}.
|
|||
Warn about C++ constructs whose meaning differs between ISO C++ 2011
|
||||
and ISO C++ 2014. This warning is enabled by @option{-Wall}.
|
||||
|
||||
@item -Wc++1z-compat @r{(C++ and Objective-C++ only)}
|
||||
@opindex Wc++1z-compat
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2014
|
||||
and the forthoming ISO C++ 2017(?). This warning is enabled by @option{-Wall}.
|
||||
|
||||
@item -Wcast-qual
|
||||
@opindex Wcast-qual
|
||||
@opindex Wno-cast-qual
|
||||
|
|
|
@ -380,6 +380,12 @@
|
|||
# error "__cpp_capture_star_this != 201603"
|
||||
#endif
|
||||
|
||||
#ifndef __cpp_noexcept_function_type
|
||||
# error "__cpp_noexcept_function_type"
|
||||
#elif __cpp_noexcept_function_type != 201510
|
||||
# error "__cpp_noexcept_function_type != 201510"
|
||||
#endif
|
||||
|
||||
#ifdef __has_cpp_attribute
|
||||
|
||||
# if ! __has_cpp_attribute(maybe_unused)
|
||||
|
|
8
gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C
Normal file
8
gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Testcase from P0012r1
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
void (*p)() throw(int);
|
||||
void (**pp)() noexcept = &p; // { dg-error "" } cannot convert to pointer to noexcept function
|
||||
|
||||
struct S { typedef void (*p)(); operator p(); };
|
||||
void (*q)() noexcept = S(); // { dg-error "" } cannot convert to pointer to noexcept function
|
3
gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C
Normal file
3
gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C
Normal file
|
@ -0,0 +1,3 @@
|
|||
// { dg-options "-Wall -std=c++14" }
|
||||
|
||||
void f(int(*)() noexcept) { } // { dg-warning "mangled" }
|
23
gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C
Normal file
23
gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C
Normal file
|
@ -0,0 +1,23 @@
|
|||
// { dg-options -std=c++1z }
|
||||
|
||||
template <class R, class... A, bool B>
|
||||
void f(R (*)(A...) noexcept(B)) { }
|
||||
|
||||
template <class R, class... A, bool B>
|
||||
void f2(R (*)(A...) noexcept(B)) { }
|
||||
|
||||
void g(int);
|
||||
void h(int) noexcept;
|
||||
|
||||
int main()
|
||||
{
|
||||
f(g);
|
||||
f2(h);
|
||||
}
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fIvJiELb0EEvPDOT1_EFT_DpT0_E" } }
|
||||
// { dg-final { scan-assembler "_Z2f2IvJiELb1EEvPDOT1_EFT_DpT0_E" } }
|
||||
|
||||
void f3(void (*)() noexcept) { }
|
||||
|
||||
// { dg-final { scan-assembler "_Z2f3PDoFvvE" } }
|
10
gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C
Normal file
10
gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Test for function pointer conversion on template arguments.
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
template <void (*P)()> struct A { };
|
||||
|
||||
void f() noexcept { };
|
||||
constexpr void (*p)() noexcept = f;
|
||||
|
||||
A<f> a;
|
||||
A<p> b;
|
13
gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C
Normal file
13
gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Test for overload resolution.
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
void f(void (*)() noexcept) = delete;
|
||||
void f(void (*)()) { }
|
||||
void g() {}
|
||||
void h() noexcept {}
|
||||
|
||||
int main()
|
||||
{
|
||||
f(g);
|
||||
f(h); // { dg-error "deleted" }
|
||||
}
|
16
gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C
Normal file
16
gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Test for deduction.
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
template <class R, class... A>
|
||||
void f(R (*)(A...));
|
||||
void g(int) noexcept;
|
||||
|
||||
template <class R, class... A>
|
||||
void h(R (*)(A...) noexcept);
|
||||
void i(int);
|
||||
|
||||
int main()
|
||||
{
|
||||
f(g);
|
||||
h(i); // { dg-error "" }
|
||||
}
|
25
gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C
Normal file
25
gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Test for composite pointer type.
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
typedef void (*P)();
|
||||
typedef void (*NP)() noexcept;
|
||||
|
||||
void f();
|
||||
void g() noexcept;
|
||||
|
||||
bool b;
|
||||
|
||||
template <class T, class U> struct Same;
|
||||
template <class T> struct Same<T,T> { };
|
||||
|
||||
Same<decltype(b ? &f : &g),P> s;
|
||||
|
||||
int main()
|
||||
{
|
||||
P p = 0;
|
||||
NP np = 0;
|
||||
|
||||
p == np;
|
||||
p != np;
|
||||
p < np;
|
||||
}
|
13
gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C
Normal file
13
gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Test for lambda conversion.
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
void f()
|
||||
{
|
||||
auto l = []() noexcept { return 0; };
|
||||
int (*p)() noexcept = l;
|
||||
int (*q)() = l;
|
||||
|
||||
auto l2 = []{ return 0; };
|
||||
p = l2; // { dg-error "" }
|
||||
q = l2;
|
||||
}
|
14
gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C
Normal file
14
gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Test for static_cast.
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
void f()
|
||||
{
|
||||
typedef void (*P)();
|
||||
typedef void (*NP)() noexcept;
|
||||
|
||||
P p;
|
||||
NP np;
|
||||
|
||||
static_cast<P>(np);
|
||||
static_cast<NP>(p); // { dg-error "" }
|
||||
}
|
22
gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C
Normal file
22
gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Test for exception handling.
|
||||
// { dg-options -std=c++1z }
|
||||
// { dg-do run }
|
||||
|
||||
void f() {}
|
||||
void g() noexcept {}
|
||||
|
||||
int main()
|
||||
{
|
||||
try { throw g; }
|
||||
catch (void (*)()) { }
|
||||
|
||||
try { throw g; }
|
||||
catch (void (*)() noexcept) { }
|
||||
|
||||
try { throw f; }
|
||||
catch (void (*)()) { }
|
||||
|
||||
try { throw f; }
|
||||
catch (void (*)() noexcept) { __builtin_abort(); }
|
||||
catch (...) { }
|
||||
}
|
18
gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C
Normal file
18
gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Test for PMF template args.
|
||||
// { dg-options -std=c++1z }
|
||||
// { dg-do run }
|
||||
|
||||
struct A
|
||||
{
|
||||
void f() noexcept;
|
||||
void g();
|
||||
};
|
||||
|
||||
template <void (A::*)()> struct B { };
|
||||
template <void (A::*)() noexcept> struct C { };
|
||||
|
||||
B<&A::f> b1;
|
||||
B<&A::g> b2;
|
||||
|
||||
C<&A::f> c1;
|
||||
C<&A::g> c2; // { dg-error "" }
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
struct S { void f (void); };
|
||||
|
||||
typedef void f1 (void) throw (int); // { dg-error "exception" }
|
||||
typedef void (*f2) (void) throw (int); // { dg-error "exception" }
|
||||
typedef void (S::*f3) (void) throw (int); // { dg-error "exception" }
|
||||
typedef void f1 (void) throw (int); // { dg-error "exception" "" { target c++14_down } }
|
||||
typedef void (*f2) (void) throw (int); // { dg-error "exception" "" { target c++14_down } }
|
||||
typedef void (S::*f3) (void) throw (int); // { dg-error "exception" "" { target c++14_down } }
|
||||
|
||||
void (*f4) (void) throw (int);
|
||||
void (S::*f5) (void) throw (int);
|
||||
|
|
|
@ -10,7 +10,7 @@ struct A
|
|||
static void (A::*pmf)() throw ();
|
||||
};
|
||||
|
||||
void (A::* A::pmf)() = &A::g;
|
||||
void (A::* A::pmf)() throw() = &A::g;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2016-11-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* demangle.h (enum demangle_component_type): Add
|
||||
DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC.
|
||||
|
||||
2016-10-17 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* dwarf2.h (enum dwarf_calling_convention): Add new DWARF5
|
||||
|
|
|
@ -449,7 +449,9 @@ enum demangle_component_type
|
|||
/* A transaction-safe function type. */
|
||||
DEMANGLE_COMPONENT_TRANSACTION_SAFE,
|
||||
/* A cloned function. */
|
||||
DEMANGLE_COMPONENT_CLONE
|
||||
DEMANGLE_COMPONENT_CLONE,
|
||||
DEMANGLE_COMPONENT_NOEXCEPT,
|
||||
DEMANGLE_COMPONENT_THROW_SPEC
|
||||
};
|
||||
|
||||
/* Types which are only used internally. */
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
2016-11-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* cp-demangle.c (is_fnqual_component_type): New.
|
||||
(d_encoding, d_print_comp_inner, d_print_mod_list): Use it.
|
||||
(FNQUAL_COMPONENT_CASE): New.
|
||||
(d_make_comp, has_return_type, d_print_comp_inner)
|
||||
(d_print_function_type): Use it.
|
||||
(next_is_type_qual): New.
|
||||
(d_cv_qualifiers, d_print_mod): Handle noexcept and throw-spec.
|
||||
|
||||
2016-11-02 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* cplus-dem.c (demangle_signature): Move fall through comment.
|
||||
|
|
|
@ -436,6 +436,8 @@ static struct demangle_component *d_operator_name (struct d_info *);
|
|||
|
||||
static struct demangle_component *d_special_name (struct d_info *);
|
||||
|
||||
static struct demangle_component *d_parmlist (struct d_info *);
|
||||
|
||||
static int d_call_offset (struct d_info *, int);
|
||||
|
||||
static struct demangle_component *d_ctor_dtor_name (struct d_info *);
|
||||
|
@ -559,6 +561,32 @@ static int d_demangle_callback (const char *, int,
|
|||
demangle_callbackref, void *);
|
||||
static char *d_demangle (const char *, int, size_t *);
|
||||
|
||||
/* True iff TYPE is a demangling component representing a
|
||||
function-type-qualifier. */
|
||||
|
||||
static int
|
||||
is_fnqual_component_type (enum demangle_component_type type)
|
||||
{
|
||||
return (type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
|
||||
|| type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| type == DEMANGLE_COMPONENT_NOEXCEPT
|
||||
|| type == DEMANGLE_COMPONENT_THROW_SPEC
|
||||
|| type == DEMANGLE_COMPONENT_REFERENCE_THIS);
|
||||
}
|
||||
|
||||
#define FNQUAL_COMPONENT_CASE \
|
||||
case DEMANGLE_COMPONENT_RESTRICT_THIS: \
|
||||
case DEMANGLE_COMPONENT_VOLATILE_THIS: \
|
||||
case DEMANGLE_COMPONENT_CONST_THIS: \
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS: \
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: \
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE: \
|
||||
case DEMANGLE_COMPONENT_NOEXCEPT: \
|
||||
case DEMANGLE_COMPONENT_THROW_SPEC
|
||||
|
||||
#ifdef CP_DEMANGLE_DEBUG
|
||||
|
||||
static void
|
||||
|
@ -984,14 +1012,9 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
|
|||
case DEMANGLE_COMPONENT_RESTRICT:
|
||||
case DEMANGLE_COMPONENT_VOLATILE:
|
||||
case DEMANGLE_COMPONENT_CONST:
|
||||
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
||||
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_ARGLIST:
|
||||
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
|
||||
FNQUAL_COMPONENT_CASE:
|
||||
break;
|
||||
|
||||
/* Other types should not be seen here. */
|
||||
|
@ -1225,12 +1248,7 @@ has_return_type (struct demangle_component *dc)
|
|||
return 0;
|
||||
case DEMANGLE_COMPONENT_TEMPLATE:
|
||||
return ! is_ctor_dtor_or_conversion (d_left (dc));
|
||||
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
||||
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
FNQUAL_COMPONENT_CASE:
|
||||
return has_return_type (d_left (dc));
|
||||
}
|
||||
}
|
||||
|
@ -1287,13 +1305,12 @@ d_encoding (struct d_info *di, int top_level)
|
|||
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
|
||||
dc = d_left (dc);
|
||||
|
||||
/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
|
||||
there may be CV-qualifiers on its right argument which
|
||||
there may be function-qualifiers on its right argument which
|
||||
really apply here; this happens when parsing a class
|
||||
which is local to a function. */
|
||||
if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
|
||||
|
@ -1301,12 +1318,7 @@ d_encoding (struct d_info *di, int top_level)
|
|||
struct demangle_component *dcr;
|
||||
|
||||
dcr = d_right (dc);
|
||||
while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
|
||||
while (is_fnqual_component_type (dcr->type))
|
||||
dcr = d_left (dcr);
|
||||
dc->u.s_binary.right = dcr;
|
||||
}
|
||||
|
@ -2239,6 +2251,24 @@ d_ctor_dtor_name (struct d_info *di)
|
|||
}
|
||||
}
|
||||
|
||||
/* True iff we're looking at an order-insensitive type-qualifier, including
|
||||
function-type-qualifiers. */
|
||||
|
||||
static int
|
||||
next_is_type_qual (struct d_info *di)
|
||||
{
|
||||
char peek = d_peek_char (di);
|
||||
if (peek == 'r' || peek == 'V' || peek == 'K')
|
||||
return 1;
|
||||
if (peek == 'D')
|
||||
{
|
||||
peek = d_peek_next_char (di);
|
||||
if (peek == 'x' || peek == 'o' || peek == 'O' || peek == 'w')
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* <type> ::= <builtin-type>
|
||||
::= <function-type>
|
||||
::= <class-enum-type>
|
||||
|
@ -2324,9 +2354,7 @@ cplus_demangle_type (struct d_info *di)
|
|||
__vector, and it treats it as order-sensitive when mangling
|
||||
names. */
|
||||
|
||||
peek = d_peek_char (di);
|
||||
if (peek == 'r' || peek == 'V' || peek == 'K'
|
||||
|| (peek == 'D' && d_peek_next_char (di) == 'x'))
|
||||
if (next_is_type_qual (di))
|
||||
{
|
||||
struct demangle_component **pret;
|
||||
|
||||
|
@ -2361,6 +2389,7 @@ cplus_demangle_type (struct d_info *di)
|
|||
|
||||
can_subst = 1;
|
||||
|
||||
peek = d_peek_char (di);
|
||||
switch (peek)
|
||||
{
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
|
||||
|
@ -2648,10 +2677,10 @@ d_cv_qualifiers (struct d_info *di,
|
|||
|
||||
pstart = pret;
|
||||
peek = d_peek_char (di);
|
||||
while (peek == 'r' || peek == 'V' || peek == 'K'
|
||||
|| (peek == 'D' && d_peek_next_char (di) == 'x'))
|
||||
while (next_is_type_qual (di))
|
||||
{
|
||||
enum demangle_component_type t;
|
||||
struct demangle_component *right = NULL;
|
||||
|
||||
d_advance (di, 1);
|
||||
if (peek == 'r')
|
||||
|
@ -2677,12 +2706,41 @@ d_cv_qualifiers (struct d_info *di,
|
|||
}
|
||||
else
|
||||
{
|
||||
t = DEMANGLE_COMPONENT_TRANSACTION_SAFE;
|
||||
di->expansion += sizeof "transaction_safe";
|
||||
d_advance (di, 1);
|
||||
peek = d_next_char (di);
|
||||
if (peek == 'x')
|
||||
{
|
||||
t = DEMANGLE_COMPONENT_TRANSACTION_SAFE;
|
||||
di->expansion += sizeof "transaction_safe";
|
||||
}
|
||||
else if (peek == 'o'
|
||||
|| peek == 'O')
|
||||
{
|
||||
t = DEMANGLE_COMPONENT_NOEXCEPT;
|
||||
di->expansion += sizeof "noexcept";
|
||||
if (peek == 'O')
|
||||
{
|
||||
right = d_expression (di);
|
||||
if (right == NULL)
|
||||
return NULL;
|
||||
if (! d_check_char (di, 'E'))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (peek == 'w')
|
||||
{
|
||||
t = DEMANGLE_COMPONENT_THROW_SPEC;
|
||||
di->expansion += sizeof "throw";
|
||||
right = d_parmlist (di);
|
||||
if (right == NULL)
|
||||
return NULL;
|
||||
if (! d_check_char (di, 'E'))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*pret = d_make_comp (di, t, NULL, NULL);
|
||||
*pret = d_make_comp (di, t, NULL, right);
|
||||
if (*pret == NULL)
|
||||
return NULL;
|
||||
pret = &d_left (*pret);
|
||||
|
@ -3973,6 +4031,8 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
|
|||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
case DEMANGLE_COMPONENT_NOEXCEPT:
|
||||
case DEMANGLE_COMPONENT_THROW_SPEC:
|
||||
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
||||
case DEMANGLE_COMPONENT_POINTER:
|
||||
case DEMANGLE_COMPONENT_COMPLEX:
|
||||
|
@ -4587,12 +4647,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
|||
adpm[i].templates = dpi->templates;
|
||||
++i;
|
||||
|
||||
if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
|
||||
if (!is_fnqual_component_type (typed_name->type))
|
||||
break;
|
||||
|
||||
typed_name = d_left (typed_name);
|
||||
|
@ -4629,13 +4684,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
|||
d_print_error (dpi);
|
||||
return;
|
||||
}
|
||||
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| (local_name->type
|
||||
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
|
||||
while (is_fnqual_component_type (local_name->type))
|
||||
{
|
||||
if (i >= sizeof adpm / sizeof adpm[0])
|
||||
{
|
||||
|
@ -4960,16 +5009,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
|||
}
|
||||
/* Fall through. */
|
||||
|
||||
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
||||
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
||||
case DEMANGLE_COMPONENT_POINTER:
|
||||
case DEMANGLE_COMPONENT_COMPLEX:
|
||||
case DEMANGLE_COMPONENT_IMAGINARY:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
FNQUAL_COMPONENT_CASE:
|
||||
modifier:
|
||||
{
|
||||
/* We keep a list of modifiers on the stack. */
|
||||
|
@ -5674,13 +5718,7 @@ d_print_mod_list (struct d_print_info *dpi, int options,
|
|||
|
||||
if (mods->printed
|
||||
|| (! suffix
|
||||
&& (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| (mods->mod->type
|
||||
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))))
|
||||
&& (is_fnqual_component_type (mods->mod->type))))
|
||||
{
|
||||
d_print_mod_list (dpi, options, mods->next, suffix);
|
||||
return;
|
||||
|
@ -5733,12 +5771,7 @@ d_print_mod_list (struct d_print_info *dpi, int options,
|
|||
dc = dc->u.s_unary_num.sub;
|
||||
}
|
||||
|
||||
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
|
||||
while (is_fnqual_component_type (dc->type))
|
||||
dc = d_left (dc);
|
||||
|
||||
d_print_comp (dpi, options, dc);
|
||||
|
@ -5777,6 +5810,24 @@ d_print_mod (struct d_print_info *dpi, int options,
|
|||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
d_append_string (dpi, " transaction_safe");
|
||||
return;
|
||||
case DEMANGLE_COMPONENT_NOEXCEPT:
|
||||
d_append_string (dpi, " noexcept");
|
||||
if (d_right (mod))
|
||||
{
|
||||
d_append_char (dpi, '(');
|
||||
d_print_comp (dpi, options, d_right (mod));
|
||||
d_append_char (dpi, ')');
|
||||
}
|
||||
return;
|
||||
case DEMANGLE_COMPONENT_THROW_SPEC:
|
||||
d_append_string (dpi, " throw");
|
||||
if (d_right (mod))
|
||||
{
|
||||
d_append_char (dpi, '(');
|
||||
d_print_comp (dpi, options, d_right (mod));
|
||||
d_append_char (dpi, ')');
|
||||
}
|
||||
return;
|
||||
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
||||
d_append_char (dpi, ' ');
|
||||
d_print_comp (dpi, options, d_right (mod));
|
||||
|
@ -5864,12 +5915,7 @@ d_print_function_type (struct d_print_info *dpi, int options,
|
|||
need_space = 1;
|
||||
need_paren = 1;
|
||||
break;
|
||||
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
||||
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
FNQUAL_COMPONENT_CASE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -6411,7 +6457,6 @@ is_ctor_or_dtor (const char *mangled,
|
|||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
default:
|
||||
dc = NULL;
|
||||
break;
|
||||
|
|
|
@ -4596,3 +4596,13 @@ __10%0__S4_0T0T0
|
|||
# Inheriting constructor
|
||||
_ZN1DCI11BEi
|
||||
D::B(int)
|
||||
|
||||
# exception-specification (C++17)
|
||||
_Z1fIvJiELb0EEvPDOT1_EFT_DpT0_E
|
||||
void f<void, int, false>(void (*)(int) noexcept(false))
|
||||
|
||||
_Z1fIvJiELb0EEvPDoFT_DpT0_E
|
||||
void f<void, int, false>(void (*)(int) noexcept)
|
||||
|
||||
_Z1fIvJiELb0EEvPDwiEFT_DpT0_E
|
||||
void f<void, int, false>(void (*)(int) throw(int))
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
2016-11-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* include/bits/c++config (_GLIBCXX_NOEXCEPT_PARM)
|
||||
(_GLIBCXX_NOEXCEPT_QUAL): New.
|
||||
* include/std/type_traits (is_function): Use them.
|
||||
* libsubc++/new (launder): Likewise.
|
||||
* libsupc++/cxxabi.h (__pbase_type_info::__masks): Add
|
||||
__noexcept_mask.
|
||||
* libsupc++/pbase_type_info.cc (__do_catch): Handle function
|
||||
pointer conversion.
|
||||
|
||||
2016-11-07 François Dumont <fdumont@gcc.gnu.org>
|
||||
|
||||
* config/abi/pre/gnu-versioned-namespace.ver: Export C++17 new of
|
||||
|
|
|
@ -146,6 +146,14 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#if __cpp_noexcept_function_type
|
||||
#define _GLIBCXX_NOEXCEPT_PARM , bool _N
|
||||
#define _GLIBCXX_NOEXCEPT_QUAL noexcept (_N)
|
||||
#else
|
||||
#define _GLIBCXX_NOEXCEPT_PARM
|
||||
#define _GLIBCXX_NOEXCEPT_QUAL
|
||||
#endif
|
||||
|
||||
// Macro for extern template, ie controlling template linkage via use
|
||||
// of extern keyword on template declaration. As documented in the g++
|
||||
// manual, it inhibits all implicit instantiations and is used
|
||||
|
|
|
@ -458,100 +458,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
struct is_function
|
||||
: public false_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...)>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......)>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) const>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) const _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) const &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) const & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) const &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) const && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) const>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) const _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) const &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) const & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) const &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) const && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) volatile>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) volatile _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) volatile &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) volatile & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) volatile &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) volatile && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) volatile>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) volatile _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) volatile &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) volatile & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) volatile &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) volatile && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) const volatile>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) const volatile _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) const volatile &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) const volatile & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes...) const volatile &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes...) const volatile && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) const volatile>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) const volatile _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) const volatile &>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) const volatile & _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
template<typename _Res, typename... _ArgTypes>
|
||||
struct is_function<_Res(_ArgTypes......) const volatile &&>
|
||||
template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
|
||||
struct is_function<_Res(_ArgTypes......) const volatile && _GLIBCXX_NOEXCEPT_QUAL>
|
||||
: public true_type { };
|
||||
|
||||
#define __cpp_lib_is_null_pointer 201309
|
||||
|
|
|
@ -279,7 +279,8 @@ namespace __cxxabiv1
|
|||
__restrict_mask = 0x4,
|
||||
__incomplete_mask = 0x8,
|
||||
__incomplete_class_mask = 0x10,
|
||||
__transaction_safe_mask = 0x20
|
||||
__transaction_safe_mask = 0x20,
|
||||
__noexcept_mask = 0x40
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
|
@ -197,10 +197,10 @@ namespace std
|
|||
// The program is ill-formed if T is a function type or
|
||||
// (possibly cv-qualified) void.
|
||||
|
||||
template<typename _Ret, typename... _Args>
|
||||
void launder(_Ret (*)(_Args...)) = delete;
|
||||
template<typename _Ret, typename... _Args>
|
||||
void launder(_Ret (*)(_Args......)) = delete;
|
||||
template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM>
|
||||
void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUAL) = delete;
|
||||
template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM>
|
||||
void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUAL) = delete;
|
||||
|
||||
void launder(void*) = delete;
|
||||
void launder(const void*) = delete;
|
||||
|
|
|
@ -80,12 +80,13 @@ __do_catch (const type_info *thr_type,
|
|||
|
||||
unsigned tflags = thrown_type->__flags;
|
||||
|
||||
bool throw_tx = (tflags & __transaction_safe_mask);
|
||||
bool catch_tx = (__flags & __transaction_safe_mask);
|
||||
if (throw_tx && !catch_tx)
|
||||
/* Catch can perform a transaction-safety conversion. */
|
||||
tflags &= ~__transaction_safe_mask;
|
||||
if (catch_tx && !throw_tx)
|
||||
const unsigned fqual_mask = __transaction_safe_mask|__noexcept_mask;
|
||||
unsigned throw_fqual = (tflags & fqual_mask);
|
||||
unsigned catch_fqual = (__flags & fqual_mask);
|
||||
if (throw_fqual & ~catch_fqual)
|
||||
/* Catch can perform a function pointer conversion. */
|
||||
tflags &= catch_fqual;
|
||||
if (catch_fqual & ~throw_fqual)
|
||||
/* But not the reverse. */
|
||||
return false;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
// { dg-error "multiple inlined namespaces" "" { target *-*-* } 342 }
|
||||
// { dg-error "multiple inlined namespaces" "" { target *-*-* } 350 }
|
||||
|
||||
// "template argument 1 is invalid"
|
||||
// { dg-prune-output "tuple:993" }
|
||||
|
|
Loading…
Add table
Reference in a new issue