+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
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");
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.
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.
enum conversion_kind {
ck_identity,
ck_lvalue,
- ck_tsafe,
+ ck_fnptr,
ck_qual,
ck_std,
ck_ptr,
break;
case ck_qual:
+ case ck_fnptr:
if (rank < cr_exact)
rank = cr_exact;
break;
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 */;
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 ()
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;
+
+ 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;
- 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;
+ 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)
{
{
/* [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));
}
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);
[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]
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:
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;
}
}
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);
}
}
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);
}
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)))
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
};
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
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);
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);
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);
/* 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;
+}
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);
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
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);
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))
The optional attribute-specifier-seq appertains to
the function type. */
decl_attributes (&type, attrs, 0);
+
+ if (raises)
+ type = build_exception_variant (type, raises);
}
break;
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. */
/* 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;
}
}
+/* <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
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;
}
{
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
write_bare_function_type (fn_type,
mangle_return_type_p (decl),
d);
+
+ if (tmpl)
+ --processing_template_decl;
}
}
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
write_CV_qualifiers_for_type (this_type);
}
+ write_exception_spec (TYPE_RAISES_EXCEPTIONS (type));
+
if (tx_safe_fn_type_p (type))
write_string ("Dx");
}
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
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
}
/* 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. */
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))
&& !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
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:
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);
}
}
+ bool fndecl_type = (complain & tf_fndecl_type);
+ complain &= ~tf_fndecl_type;
+
if (type
&& code != TYPENAME_TYPE
&& code != TEMPLATE_TYPE_PARM
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)
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;
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:
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,
return cxx_printable_name_internal (decl, v, true);
}
\f
+/* 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. */
/* 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;
}
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)
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);
}
/* 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
/* 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
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
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
# 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)
--- /dev/null
+// 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
--- /dev/null
+// { dg-options "-Wall -std=c++14" }
+
+void f(int(*)() noexcept) { } // { dg-warning "mangled" }
--- /dev/null
+// { 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" } }
--- /dev/null
+// 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;
--- /dev/null
+// 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" }
+}
--- /dev/null
+// 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 "" }
+}
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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 "" }
+}
--- /dev/null
+// 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 (...) { }
+}
--- /dev/null
+// 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 "" }
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);
static void (A::*pmf)() throw ();
};
-void (A::* A::pmf)() = &A::g;
+void (A::* A::pmf)() throw() = &A::g;
int main()
{
+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
/* 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. */
+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.
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 *);
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
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. */
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));
}
}
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)
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;
}
}
}
+/* 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>
__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;
can_subst = 1;
+ peek = d_peek_char (di);
switch (peek)
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
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')
}
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);
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:
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);
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])
{
}
/* 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. */
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;
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);
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));
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;
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;
# 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))
+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
# 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
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
__restrict_mask = 0x4,
__incomplete_mask = 0x8,
__incomplete_class_mask = 0x10,
- __transaction_safe_mask = 0x20
+ __transaction_safe_mask = 0x20,
+ __noexcept_mask = 0x40
};
protected:
// 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;
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;
#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" }