diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-04-10 10:21:19 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-04-10 10:21:19 -0700 |
commit | 3cdc95b9f8d6c90c4a279783fd3da961c5afb22c (patch) | |
tree | d077f53179e7b563e42ea71b385e59912a45d055 /gcc/cp | |
parent | caf99f28b0311c3ffb368819218e7ce4d245627e (diff) | |
parent | e26bd694c790b7c8f68c6736b2683c60a8fcbcfe (diff) | |
download | gcc-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/ChangeLog | 76 | ||||
-rw-r--r-- | gcc/cp/call.c | 14 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 13 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 45 | ||||
-rw-r--r-- | gcc/cp/decl.c | 53 | ||||
-rw-r--r-- | gcc/cp/method.c | 11 | ||||
-rw-r--r-- | gcc/cp/parser.c | 36 | ||||
-rw-r--r-- | gcc/cp/pt.c | 162 |
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 (); |