aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-04-10 10:21:19 -0700
committerIan Lance Taylor <iant@golang.org>2020-04-10 10:21:19 -0700
commit3cdc95b9f8d6c90c4a279783fd3da961c5afb22c (patch)
treed077f53179e7b563e42ea71b385e59912a45d055 /gcc/cp
parentcaf99f28b0311c3ffb368819218e7ce4d245627e (diff)
parente26bd694c790b7c8f68c6736b2683c60a8fcbcfe (diff)
downloadgcc-3cdc95b9f8d6c90c4a279783fd3da961c5afb22c.zip
gcc-3cdc95b9f8d6c90c4a279783fd3da961c5afb22c.tar.gz
gcc-3cdc95b9f8d6c90c4a279783fd3da961c5afb22c.tar.bz2
Merge from trunk revision e26bd694c790b7c8f68c6736b2683c60a8fcbcfe
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog76
-rw-r--r--gcc/cp/call.c14
-rw-r--r--gcc/cp/constexpr.c13
-rw-r--r--gcc/cp/coroutines.cc45
-rw-r--r--gcc/cp/decl.c53
-rw-r--r--gcc/cp/method.c11
-rw-r--r--gcc/cp/parser.c36
-rw-r--r--gcc/cp/pt.c162
8 files changed, 321 insertions, 89 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 60d9279..38f86cd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,79 @@
+2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com>
+
+ * coroutines.cc (co_await_expander): Simplify.
+
+2020-04-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/94523
+ * constexpr.c (cxx_eval_constant_expression) [VAR_DECL]: Look at
+ ctx->object and ctx->global->values first.
+
+2020-04-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/93790
+ * call.c (initialize_reference): If the reference binding failed, maybe
+ try initializing from { }.
+ * decl.c (grok_reference_init): For T& t(e), set
+ LOOKUP_AGGREGATE_PAREN_INIT but don't build up a constructor yet.
+
+2020-04-08 Iain Sandoe <iain@sandoe.co.uk>
+ Jun Ma <JunMa@linux.alibaba.com>
+
+ * coroutines.cc (maybe_promote_captured_temps): Add a cleanup
+ expression, if needed, to any call from which we promoted
+ temporaries captured by reference.
+
+2020-04-08 Marek Polacek <polacek@redhat.com>
+
+ PR c++/94507 - ICE-on-invalid with lambda template.
+ * pt.c (tsubst_lambda_expr): Cope when tsubst_template_decl or
+ tsubst_function_decl returns error_mark_node.
+
+2020-04-08 Martin Liska <mliska@suse.cz>
+
+ PR c++/94314
+ * decl.c (duplicate_decls): Duplicate also DECL_IS_REPLACEABLE_OPERATOR.
+ (cxx_init_decl_processing): Mark replaceable all implicitly defined
+ operators.
+
+2020-04-08 Patrick Palka <ppalka@redhat.com>
+
+ Core issues 1001 and 1322
+ PR c++/92010
+ * pt.c (rebuild_function_or_method_type): Split function out from ...
+ (tsubst_function_type): ... here.
+ (maybe_rebuild_function_decl_type): New function.
+ (tsubst_function_decl): Use it.
+
+2020-04-08 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/94325
+ * decl.c (begin_destructor_body): For CLASSTYPE_VBASECLASSES class
+ dtors, if CLASSTYPE_PRIMARY_BINFO is non-NULL, but not BINFO_VIRTUAL_P,
+ look at CLASSTYPE_PRIMARY_BINFO of its BINFO_TYPE if it is not
+ BINFO_VIRTUAL_P, and so on.
+
+2020-04-08 Marek Polacek <polacek@redhat.com>
+
+ PR c++/94478 - ICE with defaulted comparison operator
+ * method.c (early_check_defaulted_comparison): Give an error when the
+ context is null.
+
+2020-04-08 Tobias Burnus <tobias@codesourcery.com>
+
+ PR middle-end/94120
+ * paser.c (cp_parser_oacc_declare): Add check that variables
+ are declared in the same scope as the directive.
+
+2020-04-07 Jason Merrill <jason@redhat.com>
+
+ PR c++/94480
+ * parser.c (cp_parser_requires_expression): Use tentative_firewall.
+
+ PR c++/94481
+ * parser.c (cp_parser_placeholder_type_specifier): Use
+ matching_parens.
+
2020-04-07 Iain Sandoe <iain@sandoe.co.uk>
* coroutines.cc (maybe_promote_captured_temps): Ensure that
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 02220ff..1f3d9d2 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -12196,6 +12196,20 @@ initialize_reference (tree type, tree expr,
conv = reference_binding (type, TREE_TYPE (expr), expr, /*c_cast_p=*/false,
flags, complain);
+ /* If this conversion failed, we're in C++20, and we have something like
+ A& a(b) where A is an aggregate, try again, this time as A& a{b}. */
+ if ((!conv || conv->bad_p)
+ && (flags & LOOKUP_AGGREGATE_PAREN_INIT))
+ {
+ tree e = build_constructor_single (init_list_type_node, NULL_TREE, expr);
+ CONSTRUCTOR_IS_DIRECT_INIT (e) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (e) = true;
+ conversion *c = reference_binding (type, TREE_TYPE (e), e,
+ /*c_cast_p=*/false, flags, complain);
+ /* If this worked, use it. */
+ if (c && !c->bad_p)
+ expr = e, conv = c;
+ }
if (!conv || conv->bad_p)
{
if (complain & tf_error)
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 96497ab..5793430 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5485,6 +5485,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
CONST_DECL for aggregate constants. */
if (lval)
return t;
+ else if (t == ctx->object)
+ return ctx->ctor;
+ if (VAR_P (t))
+ if (tree *p = ctx->global->values.get (t))
+ if (*p != NULL_TREE)
+ {
+ r = *p;
+ break;
+ }
if (COMPLETE_TYPE_P (TREE_TYPE (t))
&& is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false))
{
@@ -5499,10 +5508,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (r) == TARGET_EXPR
&& TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
r = TARGET_EXPR_INITIAL (r);
- if (VAR_P (r))
- if (tree *p = ctx->global->values.get (r))
- if (*p != NULL_TREE)
- r = *p;
if (DECL_P (r))
{
if (!ctx->quiet)
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 983fa65..ab06c0a 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1389,34 +1389,13 @@ co_await_expander (tree *stmt, int * /*do_subtree*/, void *d)
return NULL_TREE;
coro_aw_data *data = (coro_aw_data *) d;
-
enum tree_code stmt_code = TREE_CODE (*stmt);
tree stripped_stmt = *stmt;
-
- /* Look inside <(void) (expr)> cleanup */
- if (stmt_code == CLEANUP_POINT_EXPR)
- {
- stripped_stmt = TREE_OPERAND (*stmt, 0);
- stmt_code = TREE_CODE (stripped_stmt);
- if (stmt_code == EXPR_STMT
- && (TREE_CODE (EXPR_STMT_EXPR (stripped_stmt)) == CONVERT_EXPR
- || TREE_CODE (EXPR_STMT_EXPR (stripped_stmt)) == CAST_EXPR)
- && VOID_TYPE_P (TREE_TYPE (EXPR_STMT_EXPR (stripped_stmt))))
- {
- stripped_stmt = TREE_OPERAND (EXPR_STMT_EXPR (stripped_stmt), 0);
- stmt_code = TREE_CODE (stripped_stmt);
- }
- }
-
tree *buried_stmt = NULL;
tree saved_co_await = NULL_TREE;
enum tree_code sub_code = NOP_EXPR;
- if (stmt_code == EXPR_STMT
- && TREE_CODE (EXPR_STMT_EXPR (stripped_stmt)) == CO_AWAIT_EXPR)
- saved_co_await
- = EXPR_STMT_EXPR (stripped_stmt); /* hopefully, a void exp. */
- else if (stmt_code == MODIFY_EXPR || stmt_code == INIT_EXPR)
+ if (stmt_code == MODIFY_EXPR || stmt_code == INIT_EXPR)
{
sub_code = TREE_CODE (TREE_OPERAND (stripped_stmt, 1));
if (sub_code == CO_AWAIT_EXPR)
@@ -1435,6 +1414,8 @@ co_await_expander (tree *stmt, int * /*do_subtree*/, void *d)
else if ((stmt_code == CONVERT_EXPR || stmt_code == NOP_EXPR)
&& TREE_CODE (TREE_OPERAND (stripped_stmt, 0)) == CO_AWAIT_EXPR)
saved_co_await = TREE_OPERAND (stripped_stmt, 0);
+ else if (stmt_code == CO_AWAIT_EXPR)
+ saved_co_await = stripped_stmt;
if (!saved_co_await)
return NULL_TREE;
@@ -2798,11 +2779,13 @@ maybe_promote_captured_temps (tree *stmt, void *d)
location_t sloc = EXPR_LOCATION (*stmt);
tree aw_bind
= build3_loc (sloc, BIND_EXPR, void_type_node, NULL, NULL, NULL);
- tree aw_statement_current;
- if (TREE_CODE (*stmt) == CLEANUP_POINT_EXPR)
- aw_statement_current = TREE_OPERAND (*stmt, 0);
- else
- aw_statement_current = *stmt;
+
+ /* Any cleanup point expression might no longer be necessary, since we
+ are removing one or more temporaries. */
+ tree aw_statement_current = *stmt;
+ if (TREE_CODE (aw_statement_current) == CLEANUP_POINT_EXPR)
+ aw_statement_current = TREE_OPERAND (aw_statement_current, 0);
+
/* Collected the scope vars we need move the temps to regular. */
tree aw_bind_body = push_stmt_list ();
tree varlist = NULL_TREE;
@@ -2843,8 +2826,12 @@ maybe_promote_captured_temps (tree *stmt, void *d)
/* Replace all instances of that temp in the original expr. */
cp_walk_tree (&aw_statement_current, replace_proxy, &pr, NULL);
}
- /* What's left should be the original statement with any temporaries
- broken out. */
+
+ /* What's left should be the original statement with any co_await
+ captured temporaries broken out. Other temporaries might remain
+ so see if we need to wrap the revised statement in a cleanup. */
+ aw_statement_current =
+ maybe_cleanup_point_expr_void (aw_statement_current);
add_stmt (aw_statement_current);
BIND_EXPR_BODY (aw_bind) = pop_stmt_list (aw_bind_body);
awpts->captured_temps.empty ();
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index a127734..1447b89 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2368,6 +2368,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
DECL_SET_IS_OPERATOR_NEW (newdecl, true);
DECL_LOOPING_CONST_OR_PURE_P (newdecl)
|= DECL_LOOPING_CONST_OR_PURE_P (olddecl);
+ DECL_IS_REPLACEABLE_OPERATOR (newdecl)
+ |= DECL_IS_REPLACEABLE_OPERATOR (olddecl);
if (merge_attr)
merge_attribute_bits (newdecl, olddecl);
@@ -4438,13 +4440,17 @@ cxx_init_decl_processing (void)
tree opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
DECL_IS_MALLOC (opnew) = 1;
DECL_SET_IS_OPERATOR_NEW (opnew, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
DECL_IS_MALLOC (opnew) = 1;
DECL_SET_IS_OPERATOR_NEW (opnew, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
tree opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
if (flag_sized_deallocation)
{
/* Also push the sized deallocation variants:
@@ -4458,8 +4464,10 @@ cxx_init_decl_processing (void)
deltype = build_exception_variant (deltype, empty_except_spec);
opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
}
if (aligned_new_threshold)
@@ -4478,9 +4486,11 @@ cxx_init_decl_processing (void)
opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
DECL_IS_MALLOC (opnew) = 1;
DECL_SET_IS_OPERATOR_NEW (opnew, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
DECL_IS_MALLOC (opnew) = 1;
DECL_SET_IS_OPERATOR_NEW (opnew, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opnew) = 1;
/* operator delete (void *, align_val_t); */
deltype = build_function_type_list (void_type_node, ptr_type_node,
@@ -4489,8 +4499,10 @@ cxx_init_decl_processing (void)
deltype = build_exception_variant (deltype, empty_except_spec);
opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
if (flag_sized_deallocation)
{
@@ -4502,8 +4514,10 @@ cxx_init_decl_processing (void)
deltype = build_exception_variant (deltype, empty_except_spec);
opdel = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
opdel = push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
DECL_SET_IS_OPERATOR_DELETE (opdel, true);
+ DECL_IS_REPLACEABLE_OPERATOR (opdel) = 1;
}
}
@@ -5554,9 +5568,22 @@ grok_reference_init (tree decl, tree type, tree init, int flags)
&& !DECL_DECOMPOSITION_P (decl)
&& (cxx_dialect >= cxx2a))
{
- init = build_constructor_from_list (init_list_type_node, init);
- CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
- CONSTRUCTOR_IS_PAREN_INIT (init) = true;
+ /* We don't know yet if we should treat const A& r(1) as
+ const A& r{1}. */
+ if (list_length (init) == 1)
+ {
+ flags |= LOOKUP_AGGREGATE_PAREN_INIT;
+ init = build_x_compound_expr_from_list (init, ELK_INIT,
+ tf_warning_or_error);
+ }
+ /* If the list had more than one element, the code is ill-formed
+ pre-C++20, so we can build a constructor right away. */
+ else
+ {
+ init = build_constructor_from_list (init_list_type_node, init);
+ CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (init) = true;
+ }
}
else
init = build_x_compound_expr_from_list (init, ELK_INIT,
@@ -16663,14 +16690,20 @@ begin_destructor_body (void)
/* If the vptr is shared with some virtual nearly empty base,
don't clear it if not in charge, the dtor of the virtual
nearly empty base will do that later. */
- if (CLASSTYPE_VBASECLASSES (current_class_type)
- && CLASSTYPE_PRIMARY_BINFO (current_class_type)
- && BINFO_VIRTUAL_P
- (CLASSTYPE_PRIMARY_BINFO (current_class_type)))
+ if (CLASSTYPE_VBASECLASSES (current_class_type))
{
- stmt = convert_to_void (stmt, ICV_STATEMENT,
- tf_warning_or_error);
- stmt = build_if_in_charge (stmt);
+ tree c = current_class_type;
+ while (CLASSTYPE_PRIMARY_BINFO (c))
+ {
+ if (BINFO_VIRTUAL_P (CLASSTYPE_PRIMARY_BINFO (c)))
+ {
+ stmt = convert_to_void (stmt, ICV_STATEMENT,
+ tf_warning_or_error);
+ stmt = build_if_in_charge (stmt);
+ break;
+ }
+ c = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (c));
+ }
}
finish_decl_cleanup (NULL_TREE, stmt);
}
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 41b9ff8..9a21bfc 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1102,6 +1102,17 @@ early_check_defaulted_comparison (tree fn)
return false;
}
+ if (!ctx)
+ {
+ if (DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR))
+ error_at (loc, "three-way comparison operator can only be defaulted "
+ "in a class definition");
+ else
+ error_at (loc, "equality comparison operator can only be defaulted "
+ "in a class definition");
+ return false;
+ }
+
if (!DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR)
&& !same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node))
{
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index fbcdc9b..fec5203 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -18367,7 +18367,7 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
/* As per the standard, require auto or decltype(auto), except in some
cases (template parameter lists, -fconcepts-ts enabled). */
- cp_token *placeholder = NULL, *open_paren = NULL, *close_paren = NULL;
+ cp_token *placeholder = NULL, *close_paren = NULL;
if (cxx_dialect >= cxx2a)
{
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
@@ -18375,12 +18375,10 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DECLTYPE))
{
placeholder = cp_lexer_consume_token (parser->lexer);
- open_paren = cp_parser_require (parser, CPP_OPEN_PAREN,
- RT_OPEN_PAREN);
+ matching_parens parens;
+ parens.require_open (parser);
cp_parser_require_keyword (parser, RID_AUTO, RT_AUTO);
- close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN,
- RT_CLOSE_PAREN,
- open_paren->location);
+ close_paren = parens.require_close (parser);
}
}
@@ -18429,7 +18427,7 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
results in an invented template parameter. */
if (parser->auto_is_implicit_function_template_parm_p)
{
- if (placeholder && token_is_decltype (placeholder))
+ if (close_paren)
{
location_t loc = make_location (placeholder->location,
placeholder->location,
@@ -27742,6 +27740,9 @@ cp_parser_requires_expression (cp_parser *parser)
gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES));
location_t loc = cp_lexer_consume_token (parser->lexer)->location;
+ /* Avoid committing to outer tentative parse. */
+ tentative_firewall firewall (parser);
+
/* This is definitely a requires-expression. */
cp_parser_commit_to_tentative_parse (parser);
@@ -40905,6 +40906,7 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok)
{
tree clauses, stmt;
bool error = false;
+ bool found_in_scope = global_bindings_p ();
clauses = cp_parser_oacc_all_clauses (parser, OACC_DECLARE_CLAUSE_MASK,
"#pragma acc declare", pragma_tok, true);
@@ -40977,6 +40979,22 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok)
break;
}
+ if (!found_in_scope)
+ for (tree d = current_binding_level->names; d; d = TREE_CHAIN (d))
+ if (d == decl)
+ {
+ found_in_scope = true;
+ break;
+ }
+ if (!found_in_scope)
+ {
+ error_at (loc,
+ "%qD must be a variable declared in the same scope as "
+ "%<#pragma acc declare%>", decl);
+ error = true;
+ continue;
+ }
+
if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))
|| lookup_attribute ("omp declare target link",
DECL_ATTRIBUTES (decl)))
@@ -40998,7 +41016,7 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok)
DECL_ATTRIBUTES (decl)
= tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl));
- if (global_bindings_p ())
+ if (current_binding_level->kind == sk_namespace)
{
symtab_node *node = symtab_node::get (decl);
if (node != NULL)
@@ -41015,7 +41033,7 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok)
}
}
- if (error || global_bindings_p ())
+ if (error || current_binding_level->kind == sk_namespace)
return NULL_TREE;
stmt = make_node (OACC_DECLARE);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6122227..050a57b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13475,6 +13475,116 @@ lookup_explicit_specifier (tree v)
return *explicit_specifier_map->get (v);
}
+/* Given T, a FUNCTION_TYPE or METHOD_TYPE, construct and return a corresponding
+ FUNCTION_TYPE or METHOD_TYPE whose return type is RETURN_TYPE, argument types
+ are ARG_TYPES, and exception specification is RAISES, and otherwise is
+ identical to T. */
+
+static tree
+rebuild_function_or_method_type (tree t, tree return_type, tree arg_types,
+ tree raises, tsubst_flags_t complain)
+{
+ gcc_assert (FUNC_OR_METHOD_TYPE_P (t));
+
+ tree new_type;
+ if (TREE_CODE (t) == FUNCTION_TYPE)
+ {
+ new_type = build_function_type (return_type, arg_types);
+ new_type = apply_memfn_quals (new_type, type_memfn_quals (t));
+ }
+ else
+ {
+ tree r = TREE_TYPE (TREE_VALUE (arg_types));
+ /* Don't pick up extra function qualifiers from the basetype. */
+ r = cp_build_qualified_type_real (r, type_memfn_quals (t), complain);
+ if (! MAYBE_CLASS_TYPE_P (r))
+ {
+ /* [temp.deduct]
+
+ Type deduction may fail for any of the following
+ reasons:
+
+ -- Attempting to create "pointer to member of T" when T
+ is not a class type. */
+ if (complain & tf_error)
+ error ("creating pointer to member function of non-class type %qT",
+ r);
+ return error_mark_node;
+ }
+
+ new_type = build_method_type_directly (r, return_type,
+ TREE_CHAIN (arg_types));
+ }
+ new_type = cp_build_type_attribute_variant (new_type, TYPE_ATTRIBUTES (t));
+
+ cp_ref_qualifier rqual = type_memfn_rqual (t);
+ bool late_return_type_p = TYPE_HAS_LATE_RETURN_TYPE (t);
+ return build_cp_fntype_variant (new_type, rqual, raises, late_return_type_p);
+}
+
+/* Check if the function type of DECL, a FUNCTION_DECL, agrees with the type of
+ each of its formal parameters. If there is a disagreement then rebuild
+ DECL's function type according to its formal parameter types, as part of a
+ resolution for Core issues 1001/1322. */
+
+static void
+maybe_rebuild_function_decl_type (tree decl)
+{
+ bool function_type_needs_rebuilding = false;
+ if (tree parm_list = FUNCTION_FIRST_USER_PARM (decl))
+ {
+ tree parm_type_list = FUNCTION_FIRST_USER_PARMTYPE (decl);
+ while (parm_type_list && parm_type_list != void_list_node)
+ {
+ tree parm_type = TREE_VALUE (parm_type_list);
+ tree formal_parm_type_unqual = strip_top_quals (TREE_TYPE (parm_list));
+ if (!same_type_p (parm_type, formal_parm_type_unqual))
+ {
+ function_type_needs_rebuilding = true;
+ break;
+ }
+
+ parm_list = DECL_CHAIN (parm_list);
+ parm_type_list = TREE_CHAIN (parm_type_list);
+ }
+ }
+
+ if (!function_type_needs_rebuilding)
+ return;
+
+ const tree fntype = TREE_TYPE (decl);
+ tree parm_list = DECL_ARGUMENTS (decl);
+ tree old_parm_type_list = TYPE_ARG_TYPES (fntype);
+ tree new_parm_type_list = NULL_TREE;
+ tree *q = &new_parm_type_list;
+ for (int skip = num_artificial_parms_for (decl); skip > 0; skip--)
+ {
+ *q = copy_node (old_parm_type_list);
+ parm_list = DECL_CHAIN (parm_list);
+ old_parm_type_list = TREE_CHAIN (old_parm_type_list);
+ q = &TREE_CHAIN (*q);
+ }
+ while (old_parm_type_list && old_parm_type_list != void_list_node)
+ {
+ *q = copy_node (old_parm_type_list);
+ tree *new_parm_type = &TREE_VALUE (*q);
+ tree formal_parm_type_unqual = strip_top_quals (TREE_TYPE (parm_list));
+ if (!same_type_p (*new_parm_type, formal_parm_type_unqual))
+ *new_parm_type = formal_parm_type_unqual;
+
+ parm_list = DECL_CHAIN (parm_list);
+ old_parm_type_list = TREE_CHAIN (old_parm_type_list);
+ q = &TREE_CHAIN (*q);
+ }
+ if (old_parm_type_list == void_list_node)
+ *q = void_list_node;
+
+ TREE_TYPE (decl)
+ = rebuild_function_or_method_type (fntype,
+ TREE_TYPE (fntype), new_parm_type_list,
+ TYPE_RAISES_EXCEPTIONS (fntype), tf_none);
+}
+
/* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL. */
static tree
@@ -13665,6 +13775,8 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
DECL_ARGUMENTS (r) = parms;
DECL_RESULT (r) = NULL_TREE;
+ maybe_rebuild_function_decl_type (r);
+
TREE_STATIC (r) = 0;
TREE_PUBLIC (r) = TREE_PUBLIC (t);
DECL_EXTERNAL (r) = 1;
@@ -14694,7 +14806,6 @@ tsubst_function_type (tree t,
{
tree return_type;
tree arg_types = NULL_TREE;
- tree fntype;
/* The TYPE_CONTEXT is not used for function/method types. */
gcc_assert (TYPE_CONTEXT (t) == NULL_TREE);
@@ -14765,42 +14876,8 @@ tsubst_function_type (tree t,
}
/* Construct a new type node and return it. */
- if (TREE_CODE (t) == FUNCTION_TYPE)
- {
- fntype = build_function_type (return_type, arg_types);
- fntype = apply_memfn_quals (fntype, type_memfn_quals (t));
- }
- else
- {
- tree r = TREE_TYPE (TREE_VALUE (arg_types));
- /* Don't pick up extra function qualifiers from the basetype. */
- r = cp_build_qualified_type_real (r, type_memfn_quals (t), complain);
- if (! MAYBE_CLASS_TYPE_P (r))
- {
- /* [temp.deduct]
-
- Type deduction may fail for any of the following
- reasons:
-
- -- Attempting to create "pointer to member of T" when T
- is not a class type. */
- if (complain & tf_error)
- error ("creating pointer to member function of non-class type %qT",
- r);
- return error_mark_node;
- }
-
- fntype = build_method_type_directly (r, return_type,
- TREE_CHAIN (arg_types));
- }
- fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t));
-
- /* See comment above. */
- tree raises = NULL_TREE;
- cp_ref_qualifier rqual = type_memfn_rqual (t);
- fntype = build_cp_fntype_variant (fntype, rqual, raises, late_return_type_p);
-
- return fntype;
+ return rebuild_function_or_method_type (t, return_type, arg_types,
+ /*raises=*/NULL_TREE, complain);
}
/* FNTYPE is a FUNCTION_TYPE or METHOD_TYPE. Substitute the template
@@ -18876,6 +18953,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (oldtmpl)
{
tmpl = tsubst_template_decl (oldtmpl, args, complain, fntype);
+ if (tmpl == error_mark_node)
+ {
+ r = error_mark_node;
+ goto out;
+ }
fn = DECL_TEMPLATE_RESULT (tmpl);
finish_member_declaration (tmpl);
}
@@ -18883,6 +18965,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
tmpl = NULL_TREE;
fn = tsubst_function_decl (oldfn, args, complain, fntype);
+ if (fn == error_mark_node)
+ {
+ r = error_mark_node;
+ goto out;
+ }
finish_member_declaration (fn);
}
@@ -18948,6 +19035,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
maybe_add_lambda_conv_op (type);
}
+out:
finish_struct (type, /*attr*/NULL_TREE);
insert_pending_capture_proxies ();