diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-10-07 15:28:36 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-10-07 15:28:36 -0700 |
commit | 0b6b70a0733672600644c8df96942cda5bf86d3d (patch) | |
tree | 9a1fbd7f782c54df55ab225ed1be057e3f3b0b8a /gcc/cp | |
parent | a5b5cabc91c38710adbe5c8a2b53882abe994441 (diff) | |
parent | fba228e259dd5112851527f2dbb62c5601100985 (diff) | |
download | gcc-0b6b70a0733672600644c8df96942cda5bf86d3d.zip gcc-0b6b70a0733672600644c8df96942cda5bf86d3d.tar.gz gcc-0b6b70a0733672600644c8df96942cda5bf86d3d.tar.bz2 |
Merge from trunk revision fba228e259dd5112851527f2dbb62c5601100985.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 234 | ||||
-rw-r--r-- | gcc/cp/class.c | 13 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 66 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 80 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 9 | ||||
-rw-r--r-- | gcc/cp/init.c | 11 | ||||
-rw-r--r-- | gcc/cp/method.c | 244 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 7 | ||||
-rw-r--r-- | gcc/cp/parser.c | 130 | ||||
-rw-r--r-- | gcc/cp/pt.c | 85 | ||||
-rw-r--r-- | gcc/cp/ptree.c | 10 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 40 | ||||
-rw-r--r-- | gcc/cp/tree.c | 13 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 115 |
15 files changed, 859 insertions, 199 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d04d84f..97d0a35 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,237 @@ +2021-10-06 Jakub Jelinek <jakub@redhat.com> + + PR c++/102612 + * parser.c (cp_parser_jump_statement): Implement C++23 P2242R3. + Allow goto expressions in constexpr function bodies for C++23. + Adjust error message for older standards to mention it. + * decl.c (start_decl): Allow static and thread_local declarations + in constexpr function bodies for C++23. Adjust error message for + older standards to mention it. + * constexpr.c (ensure_literal_type_for_constexpr_object): Allow + declarations of variables with non-literal type in constexpr function + bodies for C++23. Adjust error message for older standards to mention + it. + (cxx_eval_constant_expression) <case DECL_EXPR>: Diagnose declarations + of initialization of static or thread_local vars. + (cxx_eval_constant_expression) <case GOTO_EXPR>: Diagnose goto + statements for C++23. + (potential_constant_expression_1) <case DECL_EXPR>: Swap the + CP_DECL_THREAD_LOCAL_P and TREE_STATIC checks. + (potential_constant_expression_1) <case LABEL_EXPR>: Allow labels for + C++23. Adjust error message for older standards to mention it. + +2021-10-06 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/98712 + PR c++/102490 + * cp-tree.h (maybe_synthesize_method): Declare. + * method.c (genericize_spaceship): Use + LOOKUP_NORMAL | LOOKUP_NONVIRTUAL | LOOKUP_DEFAULTED instead of + LOOKUP_NORMAL for flags. + (comp_info): Remove defining member. Add complain, code, retcat. + (comp_info::comp_info): Adjust. + (do_one_comp): Split out from build_comparison_op. Use + LOOKUP_NORMAL | LOOKUP_NONVIRTUAL | LOOKUP_DEFAULTED instead of + LOOKUP_NORMAL for flags. + (build_comparison_op): Add defining argument. Adjust comp_info + construction. Use defining instead of info.defining. Assert that + if defining, ctype is a complete type. Walk base binfos. + (synthesize_method, maybe_explain_implicit_delete, + explain_implicit_non_constexpr): Adjust build_comparison_op callers. + (maybe_synthesize_method): New function. + * class.c (check_bases_and_members): Don't call defaulted_late_check + for sfk_comparison. + (finish_struct_1): Call it here instead after class has been + completed. + * pt.c (maybe_instantiate_noexcept): Call maybe_synthesize_method + instead of synthesize_method. + +2021-10-05 Jakub Jelinek <jakub@redhat.com> + + PR c++/102548 + * tree.c (apply_identity_attributes): Fix handling of the + case where an attribute in the list doesn't affect type + identity but some attribute before it does. + +2021-10-05 Patrick Palka <ppalka@redhat.com> + + PR c++/102547 + * constexpr.c (potential_constant_expression_1): Handle + NONTYPE_ARGUMENT_PACK. + +2021-10-05 Patrick Palka <ppalka@redhat.com> + + PR c++/98930 + * pt.c (has_value_dependent_address): Return true for a static + local variable from a function template. + +2021-10-04 Marek Polacek <polacek@redhat.com> + + PR c++/97573 + * typeck.c (cp_build_binary_op): Call do_warn_array_compare. + +2021-10-03 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/101765 + * coroutines.cc (register_local_var_uses): Emit a sorry if + we encounter a VLA in the coroutine local variables. + +2021-10-03 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/99710 + * coroutines.cc (await_statement_walker): Report an error if + an await expression is found in a handler body. + +2021-10-03 John Eivind Helset <jehelset@gmail.com> + + PR c++/100673 + * coroutines.cc (build_co_await): Guard against NULL + await_suspend types. + +2021-10-03 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/101133 + * coroutines.cc (build_co_await): Mark co_await_expr trees + with TREE_SIDE_EFFECTS, also mark any containing expression. + (finish_co_await_expr): Mark type-dependent co_await_expr + trees with TREE_SIDE_EFFECTS. + +2021-10-03 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/99575 + * coroutines.cc (build_co_await): Strip NOPs from + candidate awaiter expressions before testing to see + if they need a temporary. + +2021-10-01 Martin Sebor <msebor@redhat.com> + + PR c/102103 + * typeck.c (warn_for_null_address): Enhance. + (cp_build_binary_op): Call it also for member pointers. + +2021-10-01 qingzhe huang <nickhuang99@hotmail.com> + + PR c++/101783 + * tree.c (cp_build_qualified_type_real): Exclude typedef from + error. + +2021-10-01 Jakub Jelinek <jakub@redhat.com> + Richard Biener <rguenther@suse.de> + + PR sanitizer/102515 + * typeck.c (cp_build_binary_op): Call ubsan_instrument_division + for division even for SANITIZE_SI_OVERFLOW. + +2021-10-01 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_order): Set + OMP_CLAUSE_ORDER_REPRODUCIBLE for explicit reproducible: modifier. + +2021-10-01 Jakub Jelinek <jakub@redhat.com> + + PR c++/102496 + * name-lookup.c (push_local_extern_decl_alias): Return early even for + tls vars with non-dependent type when processing_template_decl. For + CP_DECL_THREAD_LOCAL_P vars call set_decl_tls_model on alias. + +2021-09-30 Patrick Palka <ppalka@redhat.com> + + PR c++/102535 + * method.c (is_xible_helper): Don't exit early for multi-arg + ctors in C++20. + +2021-09-30 Patrick Palka <ppalka@redhat.com> + + * parser.c (cp_parser_trait_expr): Call nreverse on the reversed + list of trailing arguments. + +2021-09-30 Patrick Palka <ppalka@redhat.com> + + PR c++/95567 + * method.c (build_comparison_op): Skip DECL_VIRTUAL_P fields. + +2021-09-28 Patrick Palka <ppalka@redhat.com> + + PR c++/99909 + * pt.c (coerce_template_template_parms): Keep + processing_template_decl set around the call to unify as well. + +2021-09-28 Iain Sandoe <iain@sandoe.co.uk> + + PR c++/102454 + * coroutines.cc (analyze_fn_parms): Clean up synthetic names for + unnamed function params. + (morph_fn_to_coro): Do not try to set a guard variable for param + DTORs in the ramp, unless we have exceptions active. + +2021-09-27 Patrick Palka <ppalka@redhat.com> + + PR c++/102479 + * pt.c (rewrite_template_parm): Handle single-level tsubst_args. + Avoid a tree cycle when assigning the DECL_TEMPLATE_PARMS for a + rewritten ttp. + (alias_ctad_tweaks): Set current_template_parms accordingly. + +2021-09-23 Michel Morin <mimomorin@gmail.com> + + * parser.c (cp_keyword_starts_decl_specifier_p): Do not + handle RID_ATTRIBUTE. + (cp_parser_constructor_declarator_p): Remove now-redundant + checks. + (cp_parser_lambda_declarator_opt): Likewise. + +2021-09-23 Michel Morin <mimomorin@gmail.com> + + PR c++/77565 + * parser.c (cp_keyword_starts_decl_specifier_p): Handle more + decl-specifiers (typedef/inline/cv/explicit/virtual/friend). + +2021-09-23 Patrick Palka <ppalka@redhat.com> + + * ptree.c (cxx_print_decl): Dump the DECL_TEMPLATE_RESULT of + a TEMPLATE_DECL. Dump the DECL_TEMPLATE_INFO rather than just + printing its pointer value. + +2021-09-23 Jakub Jelinek <jakub@redhat.com> + + PR c++/102413 + * parser.c (cp_parser_omp_directive_args): Diagnose if omp::directive + is not followed by a balanced token sequence starting with open paren. + +2021-09-22 Patrick Palka <ppalka@redhat.com> + + DR 2446 + PR c++/102412 + * constexpr.c (cxx_eval_constant_expression) + <case TEMPLATE_ID_EXPR>: Check value_dependent_expression_p + instead of processing_template_decl. + * pt.c (value_dependent_expression_p) <case TEMPLATE_ID_EXPR>: + Return true only if any_dependent_template_arguments_p. + (instantiation_dependent_r) <case CALL_EXPR>: Remove this case. + <case TEMPLATE_ID_EXPR>: Likewise. + +2021-09-22 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_allocate): Parse allocate clause + modifiers. + * semantics.c (finish_omp_clauses) <OMP_CLAUSE_ALLOCATE>: Perform + semantic analysis of OMP_CLAUSE_ALLOCATE_ALIGN. + * pt.c (tsubst_omp_clauses) <case OMP_CLAUSE_ALLOCATE>: Handle + also OMP_CLAUSE_ALLOCATE_ALIGN. + +2021-09-22 Barrett Adair <barrettellisadair@gmail.com> + + * pt.c (find_parm_usage_r): New walk_tree callback to find func + parms. + (any_template_arguments_need_structural_equality_p): New special + case. + +2021-09-21 wangpc <pc.wang@linux.alibaba.com> + + * decl.c (start_decl_1): Move verify_type_context to ... + (cp_finish_decl): ... to here. + 2021-09-18 Jakub Jelinek <jakub@redhat.com> * parser.c (cp_parser_omp_clause_order): Parse unconstrained diff --git a/gcc/cp/class.c b/gcc/cp/class.c index fe225c6..5961162 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6119,6 +6119,10 @@ check_bases_and_members (tree t) && !DECL_ARTIFICIAL (fn) && DECL_DEFAULTED_IN_CLASS_P (fn)) { + /* ...except handle comparisons later, in finish_struct_1. */ + if (special_function_p (fn) == sfk_comparison) + continue; + int copy = copy_fn_p (fn); if (copy > 0) { @@ -7467,7 +7471,14 @@ finish_struct_1 (tree t) for any static member objects of the type we're working on. */ for (x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x)) if (DECL_DECLARES_FUNCTION_P (x)) - DECL_IN_AGGR_P (x) = false; + { + /* Synthesize constexpr defaulted comparisons. */ + if (!DECL_ARTIFICIAL (x) + && DECL_DEFAULTED_IN_CLASS_P (x) + && special_function_p (x) == sfk_comparison) + defaulted_late_check (x); + DECL_IN_AGGR_P (x) = false; + } else if (VAR_P (x) && TREE_STATIC (x) && TREE_TYPE (x) != error_mark_node && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (x)), t)) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 8a5dd06..66d5221 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -109,14 +109,15 @@ ensure_literal_type_for_constexpr_object (tree decl) explain_non_literal_class (type); decl = error_mark_node; } - else + else if (cxx_dialect < cxx23) { if (!is_instantiation_of_constexpr (current_function_decl)) { auto_diagnostic_group d; error_at (DECL_SOURCE_LOCATION (decl), "variable %qD of non-literal type %qT in " - "%<constexpr%> function", decl, type); + "%<constexpr%> function only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>", decl, type); explain_non_literal_class (type); decl = error_mark_node; } @@ -6345,6 +6346,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = void_node; break; } + + if (VAR_P (r) + && (TREE_STATIC (r) || CP_DECL_THREAD_LOCAL_P (r)) + /* Allow __FUNCTION__ etc. */ + && !DECL_ARTIFICIAL (r)) + { + gcc_assert (cxx_dialect >= cxx23); + if (!ctx->quiet) + { + if (CP_DECL_THREAD_LOCAL_P (r)) + error_at (loc, "control passes through declaration of %qD " + "with thread storage duration", r); + else + error_at (loc, "control passes through declaration of %qD " + "with static storage duration", r); + } + *non_constant_p = true; + break; + } + if (AGGREGATE_TYPE_P (TREE_TYPE (r)) || VECTOR_TYPE_P (TREE_TYPE (r))) { @@ -7049,10 +7070,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; case GOTO_EXPR: - *jump_target = TREE_OPERAND (t, 0); - gcc_assert (breaks (jump_target) || continues (jump_target) - /* Allow for jumping to a cdtor_label. */ - || returns (jump_target)); + if (breaks (&TREE_OPERAND (t, 0)) + || continues (&TREE_OPERAND (t, 0)) + /* Allow for jumping to a cdtor_label. */ + || returns (&TREE_OPERAND (t, 0))) + *jump_target = TREE_OPERAND (t, 0); + else + { + gcc_assert (cxx_dialect >= cxx23); + if (!ctx->quiet) + error_at (loc, "%<goto%> is not a constant expression"); + *non_constant_p = true; + } break; case LOOP_EXPR: @@ -7117,7 +7146,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; } - if (!processing_template_decl + if (!value_dependent_expression_p (t) && !uid_sensitive_constexpr_evaluation_p ()) r = evaluate_concept_check (t); else @@ -8736,18 +8765,18 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, tmp = DECL_EXPR_DECL (t); if (VAR_P (tmp) && !DECL_ARTIFICIAL (tmp)) { - if (TREE_STATIC (tmp)) + if (CP_DECL_THREAD_LOCAL_P (tmp)) { if (flags & tf_error) error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared " - "%<static%> in %<constexpr%> context", tmp); + "%<thread_local%> in %<constexpr%> context", tmp); return false; } - else if (CP_DECL_THREAD_LOCAL_P (tmp)) + else if (TREE_STATIC (tmp)) { if (flags & tf_error) error_at (DECL_SOURCE_LOCATION (tmp), "%qD declared " - "%<thread_local%> in %<constexpr%> context", tmp); + "%<static%> in %<constexpr%> context", tmp); return false; } else if (!check_for_uninitialized_const_var @@ -9025,10 +9054,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case LABEL_EXPR: t = LABEL_EXPR_LABEL (t); - if (DECL_ARTIFICIAL (t)) + if (DECL_ARTIFICIAL (t) || cxx_dialect >= cxx23) return true; else if (flags & tf_error) - error_at (loc, "label definition is not a constant expression"); + error_at (loc, "label definition in %<constexpr%> function only " + "available with %<-std=c++2b%> or %<-std=gnu++2b%>"); return false; case ANNOTATE_EXPR: @@ -9043,6 +9073,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case CO_RETURN_EXPR: return false; + case NONTYPE_ARGUMENT_PACK: + { + tree args = ARGUMENT_PACK_ARGS (t); + int len = TREE_VEC_LENGTH (args); + for (int i = 0; i < len; ++i) + if (!RECUR (TREE_VEC_ELT (args, i), any)) + return false; + return true; + } + default: if (objc_non_constant_expr_p (t)) return false; diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index fbd5c49..9017902 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1008,6 +1008,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) } /* Only build a temporary if we need it. */ + STRIP_NOPS (e_proxy); if (TREE_CODE (e_proxy) == PARM_DECL || (VAR_P (e_proxy) && !is_local_temp (e_proxy))) { @@ -1052,7 +1053,8 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) else if (same_type_p (susp_return_type, boolean_type_node)) ok = true; else if (TREE_CODE (susp_return_type) == RECORD_TYPE - && CLASS_TYPE_P (susp_return_type)) + && CLASS_TYPE_P (susp_return_type) + && CLASSTYPE_TEMPLATE_INFO (susp_return_type)) { tree tt = CLASSTYPE_TI_TEMPLATE (susp_return_type); if (tt == coro_handle_templ) @@ -1116,13 +1118,15 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) a, e_proxy, o, awaiter_calls, build_int_cst (integer_type_node, (int) suspend_kind)); + TREE_SIDE_EFFECTS (await_expr) = true; if (te) { TREE_OPERAND (te, 1) = await_expr; + TREE_SIDE_EFFECTS (te) = true; await_expr = te; } - tree t = convert_from_reference (await_expr); - return t; + SET_EXPR_LOCATION (await_expr, loc); + return convert_from_reference (await_expr); } tree @@ -1148,8 +1152,13 @@ finish_co_await_expr (location_t kw, tree expr) co_await with the expression unchanged. */ tree functype = TREE_TYPE (current_function_decl); if (dependent_type_p (functype) || type_dependent_expression_p (expr)) - return build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr, - NULL_TREE, NULL_TREE, NULL_TREE, integer_zero_node); + { + tree aw_expr = build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr, + NULL_TREE, NULL_TREE, NULL_TREE, + integer_zero_node); + TREE_SIDE_EFFECTS (aw_expr) = true; + return aw_expr; + } /* We must be able to look up the "await_transform" method in the scope of the promise type, and obtain its return type. */ @@ -1186,14 +1195,7 @@ finish_co_await_expr (location_t kw, tree expr) } /* Now we want to build co_await a. */ - tree op = build_co_await (kw, a, CO_AWAIT_SUSPEND_POINT); - if (op != error_mark_node) - { - TREE_SIDE_EFFECTS (op) = 1; - SET_EXPR_LOCATION (op, kw); - } - - return op; + return build_co_await (kw, a, CO_AWAIT_SUSPEND_POINT); } /* Take the EXPR given and attempt to build: @@ -3686,7 +3688,22 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) *do_subtree = 0; return res; } - break; + break; + case HANDLER: + { + /* [expr.await] An await-expression shall appear only in a + potentially-evaluated expression within the compound-statement + of a function-body outside of a handler. */ + tree *await_ptr; + hash_set<tree> visited; + if (!(cp_walk_tree (&HANDLER_BODY (expr), find_any_await, + &await_ptr, &visited))) + return NULL_TREE; /* All OK. */ + location_t loc = EXPR_LOCATION (*await_ptr); + error_at (loc, "await expressions are not permitted in handlers"); + return NULL_TREE; /* This is going to fail later anyway. */ + } + break; } else if (EXPR_P (expr)) { @@ -3829,13 +3846,13 @@ analyze_fn_parms (tree orig) if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (parm.frame_type)) { - char *buf = xasprintf ("_Coro_%s_live", IDENTIFIER_POINTER (name)); - parm.guard_var = build_lang_decl (VAR_DECL, get_identifier (buf), - boolean_type_node); + char *buf = xasprintf ("%s%s_live", DECL_NAME (arg) ? "_Coro_" : "", + IDENTIFIER_POINTER (name)); + parm.guard_var + = coro_build_artificial_var (UNKNOWN_LOCATION, get_identifier (buf), + boolean_type_node, orig, + boolean_false_node); free (buf); - DECL_ARTIFICIAL (parm.guard_var) = true; - DECL_CONTEXT (parm.guard_var) = orig; - DECL_INITIAL (parm.guard_var) = boolean_false_node; parm.trivial_dtor = false; } else @@ -3910,6 +3927,16 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) if (local_var.is_static) continue; + poly_uint64 size; + if (TREE_CODE (lvtype) == ARRAY_TYPE + && !poly_int_tree_p (DECL_SIZE_UNIT (lvar), &size)) + { + sorry_at (local_var.def_loc, "variable length arrays are not" + " yet supported in coroutines"); + /* Ignore it, this is broken anyway. */ + continue; + } + lvd->local_var_seen = true; /* If this var is a lambda capture proxy, we want to leave it alone, and later rewrite the DECL_VALUE_EXPR to indirect through the @@ -4843,11 +4870,14 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) NULL, parm.frame_type, LOOKUP_NORMAL, tf_warning_or_error); - /* This var is now live. */ - r = build_modify_expr (fn_start, parm.guard_var, - boolean_type_node, INIT_EXPR, fn_start, - boolean_true_node, boolean_type_node); - finish_expr_stmt (r); + if (flag_exceptions) + { + /* This var is now live. */ + r = build_modify_expr (fn_start, parm.guard_var, + boolean_type_node, INIT_EXPR, fn_start, + boolean_true_node, boolean_type_node); + finish_expr_stmt (r); + } } } } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1fcd50c..5248ecd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7013,6 +7013,7 @@ extern void explain_implicit_non_constexpr (tree); extern bool deduce_inheriting_ctor (tree); extern bool decl_remember_implicit_trigger_p (tree); extern void synthesize_method (tree); +extern void maybe_synthesize_method (tree); extern tree lazily_declare_fn (special_function_kind, tree); extern tree skip_artificial_parms_for (const_tree, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 722e540..2d30c79 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5709,17 +5709,20 @@ start_decl (const cp_declarator *declarator, } if (current_function_decl && VAR_P (decl) - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && cxx_dialect < cxx23) { bool ok = false; if (CP_DECL_THREAD_LOCAL_P (decl)) error_at (DECL_SOURCE_LOCATION (decl), - "%qD declared %<thread_local%> in %qs function", decl, + "%qD declared %<thread_local%> in %qs function only " + "available with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, DECL_IMMEDIATE_FUNCTION_P (current_function_decl) ? "consteval" : "constexpr"); else if (TREE_STATIC (decl)) error_at (DECL_SOURCE_LOCATION (decl), - "%qD declared %<static%> in %qs function", decl, + "%qD declared %<static%> in %qs function only available " + "with %<-std=c++2b%> or %<-std=gnu++2b%>", decl, DECL_IMMEDIATE_FUNCTION_P (current_function_decl) ? "consteval" : "constexpr"); else diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1426f9a..771a19b 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -749,8 +749,15 @@ maybe_warn_list_ctor (tree member, tree init) || !is_list_ctor (current_function_decl)) return; - tree parms = FUNCTION_FIRST_USER_PARMTYPE (current_function_decl); - tree initlist = non_reference (TREE_VALUE (parms)); + tree parm = FUNCTION_FIRST_USER_PARMTYPE (current_function_decl); + parm = TREE_VALUE (parm); + tree initlist = non_reference (parm); + + /* Do not warn if the parameter is an lvalue reference to non-const. */ + if (TYPE_REF_P (parm) && !TYPE_REF_IS_RVALUE (parm) + && !CP_TYPE_CONST_P (initlist)) + return; + tree targs = CLASSTYPE_TI_ARGS (initlist); tree elttype = TREE_VEC_ELT (targs, 0); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 32f7186..1023aef 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1288,21 +1288,19 @@ struct comp_info { tree fndecl; location_t loc; - bool defining; + tsubst_flags_t complain; + tree_code code; + comp_cat_tag retcat; bool first_time; bool constexp; bool was_constexp; bool noex; - comp_info (tree fndecl, tsubst_flags_t &complain) - : fndecl (fndecl) + comp_info (tree fndecl, tsubst_flags_t complain) + : fndecl (fndecl), complain (complain) { loc = DECL_SOURCE_LOCATION (fndecl); - /* We only have tf_error set when we're called from - explain_invalid_constexpr_fn or maybe_explain_implicit_delete. */ - defining = !(complain & tf_error); - first_time = DECL_MAYBE_DELETED (fndecl); DECL_MAYBE_DELETED (fndecl) = false; @@ -1358,23 +1356,99 @@ struct comp_info } }; +/* Subroutine of build_comparison_op, to compare a single subobject. */ + +static tree +do_one_comp (location_t loc, const comp_info &info, tree sub, tree lhs, tree rhs) +{ + const tree_code code = info.code; + const tree fndecl = info.fndecl; + const comp_cat_tag retcat = info.retcat; + const tsubst_flags_t complain = info.complain; + + tree overload = NULL_TREE; + int flags = LOOKUP_NORMAL | LOOKUP_NONVIRTUAL | LOOKUP_DEFAULTED; + /* If we have an explicit comparison category return type we can fall back + to </=, so don't give an error yet if <=> lookup fails. */ + bool tentative = retcat != cc_last; + tree comp = build_new_op (loc, code, flags, lhs, rhs, + NULL_TREE, &overload, + tentative ? tf_none : complain); + + if (code != SPACESHIP_EXPR) + return comp; + + tree rettype = TREE_TYPE (TREE_TYPE (fndecl)); + + if (comp == error_mark_node) + { + if (overload == NULL_TREE && (tentative || complain)) + { + /* No viable <=>, try using op< and op==. */ + tree lteq = genericize_spaceship (loc, rettype, lhs, rhs); + if (lteq != error_mark_node) + { + /* We found usable < and ==. */ + if (retcat != cc_last) + /* Return type is a comparison category, use them. */ + comp = lteq; + else if (complain & tf_error) + /* Return type is auto, suggest changing it. */ + inform (info.loc, "changing the return type from %qs " + "to a comparison category type will allow the " + "comparison to use %qs and %qs", "auto", + "operator<", "operator=="); + } + else if (tentative && complain) + /* No usable < and ==, give an error for op<=>. */ + build_new_op (loc, code, flags, lhs, rhs, complain); + } + if (comp == error_mark_node) + return error_mark_node; + } + + if (FNDECL_USED_AUTO (fndecl) + && cat_tag_for (TREE_TYPE (comp)) == cc_last) + { + /* The operator function is defined as deleted if ... Ri is not a + comparison category type. */ + if (complain & tf_error) + inform (loc, + "three-way comparison of %qD has type %qT, not a " + "comparison category type", sub, TREE_TYPE (comp)); + return error_mark_node; + } + else if (!FNDECL_USED_AUTO (fndecl) + && !can_convert (rettype, TREE_TYPE (comp), complain)) + { + if (complain & tf_error) + error_at (loc, + "three-way comparison of %qD has type %qT, which " + "does not convert to %qT", + sub, TREE_TYPE (comp), rettype); + return error_mark_node; + } + + return comp; +} + /* Build up the definition of a defaulted comparison operator. Unlike other defaulted functions that use synthesized_method_walk to determine whether the function is e.g. deleted, for comparisons we use the same code. We try to use synthesize_method at the earliest opportunity and bail out if the function ends up being deleted. */ -static void -build_comparison_op (tree fndecl, tsubst_flags_t complain) +void +build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain) { comp_info info (fndecl, complain); - if (!info.defining && !(complain & tf_error) && !DECL_MAYBE_DELETED (fndecl)) + if (!defining && !(complain & tf_error) && !DECL_MAYBE_DELETED (fndecl)) return; int flags = LOOKUP_NORMAL; const ovl_op_info_t *op = IDENTIFIER_OVL_OP_INFO (DECL_NAME (fndecl)); - tree_code code = op->tree_code; + tree_code code = info.code = op->tree_code; tree lhs = DECL_ARGUMENTS (fndecl); tree rhs = DECL_CHAIN (lhs); @@ -1384,6 +1458,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) lhs = convert_from_reference (lhs); rhs = convert_from_reference (rhs); tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (lhs)); + gcc_assert (!defining || COMPLETE_TYPE_P (ctype)); iloc_sentinel ils (info.loc); @@ -1399,7 +1474,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) } tree compound_stmt = NULL_TREE; - if (info.defining) + if (defining) compound_stmt = begin_compound_stmt (0); else ++cp_unevaluated_operand; @@ -1413,19 +1488,44 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) if (code == EQ_EXPR || code == SPACESHIP_EXPR) { - comp_cat_tag retcat = cc_last; + comp_cat_tag &retcat = (info.retcat = cc_last); if (code == SPACESHIP_EXPR && !FNDECL_USED_AUTO (fndecl)) retcat = cat_tag_for (rettype); bool bad = false; auto_vec<tree> comps; - /* Compare each of the subobjects. Note that we get bases from - next_initializable_field because we're past C++17. */ + /* Compare the base subobjects. We handle them this way, rather than in + the field loop below, because maybe_instantiate_noexcept might bring + us here before we've built the base fields. */ + for (tree base_binfo : BINFO_BASE_BINFOS (TYPE_BINFO (ctype))) + { + tree lhs_base + = build_base_path (PLUS_EXPR, lhs, base_binfo, 0, complain); + tree rhs_base + = build_base_path (PLUS_EXPR, rhs, base_binfo, 0, complain); + + location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (ctype)); + tree comp = do_one_comp (loc, info, BINFO_TYPE (base_binfo), + lhs_base, rhs_base); + if (comp == error_mark_node) + { + bad = true; + continue; + } + + comps.safe_push (comp); + } + + /* Now compare the field subobjects. */ for (tree field = next_initializable_field (TYPE_FIELDS (ctype)); field; field = next_initializable_field (DECL_CHAIN (field))) { + if (DECL_VIRTUAL_P (field) || DECL_FIELD_IS_BASE (field)) + /* We ignore the vptr, and we already handled bases. */ + continue; + tree expr_type = TREE_TYPE (field); location_t field_loc = DECL_SOURCE_LOCATION (field); @@ -1474,8 +1574,8 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) break; tree idx; /* [1] array, no loop needed, just add [0] ARRAY_REF. - Similarly if !info.defining. */ - if (integer_zerop (maxval) || !info.defining) + Similarly if !defining. */ + if (integer_zerop (maxval) || !defining) idx = size_zero_node; /* Some other array, will need runtime loop. */ else @@ -1492,69 +1592,13 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) if (TREE_CODE (expr_type) == ARRAY_TYPE) continue; - tree overload = NULL_TREE; - tree comp = build_new_op (field_loc, code, flags, lhs_mem, rhs_mem, - NULL_TREE, &overload, - retcat != cc_last ? tf_none : complain); + tree comp = do_one_comp (field_loc, info, field, lhs_mem, rhs_mem); if (comp == error_mark_node) { - if (overload == NULL_TREE && code == SPACESHIP_EXPR - && (retcat != cc_last || complain)) - { - tree comptype = (retcat != cc_last ? rettype - : DECL_SAVED_AUTO_RETURN_TYPE (fndecl)); - /* No viable <=>, try using op< and op==. */ - tree lteq = genericize_spaceship (field_loc, comptype, - lhs_mem, rhs_mem); - if (lteq != error_mark_node) - { - /* We found usable < and ==. */ - if (retcat != cc_last) - /* Return type is a comparison category, use them. */ - comp = lteq; - else if (complain & tf_error) - /* Return type is auto, suggest changing it. */ - inform (info.loc, "changing the return type from %qs " - "to a comparison category type will allow the " - "comparison to use %qs and %qs", "auto", - "operator<", "operator=="); - } - else if (retcat != cc_last && complain != tf_none) - /* No usable < and ==, give an error for op<=>. */ - build_new_op (field_loc, code, flags, lhs_mem, rhs_mem, - complain); - } - if (comp == error_mark_node) - { - bad = true; - continue; - } - } - if (code != SPACESHIP_EXPR) - ; - else if (FNDECL_USED_AUTO (fndecl) - && cat_tag_for (TREE_TYPE (comp)) == cc_last) - { - /* The operator function is defined as deleted if ... Ri is not a - comparison category type. */ - if (complain & tf_error) - inform (field_loc, - "three-way comparison of %qD has type %qT, not a " - "comparison category type", field, TREE_TYPE (comp)); - bad = true; - continue; - } - else if (!FNDECL_USED_AUTO (fndecl) - && !can_convert (rettype, TREE_TYPE (comp), complain)) - { - if (complain & tf_error) - error_at (field_loc, - "three-way comparison of %qD has type %qT, which " - "does not convert to %qT", - field, TREE_TYPE (comp), rettype); bad = true; continue; } + /* Most of the time, comp is the expression that should be evaluated to compare the two members. If the expression needs to be evaluated more than once in a loop, it will be a TREE_LIST @@ -1584,7 +1628,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) tree comp = comps[i]; tree eq, retval = NULL_TREE, if_ = NULL_TREE; tree loop_indexes = NULL_TREE; - if (info.defining) + if (defining) { if (TREE_CODE (comp) == TREE_LIST) { @@ -1632,7 +1676,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) comp = build_static_cast (input_location, rettype, comp, complain); info.check (comp); - if (info.defining) + if (defining) { tree var = create_temporary_var (rettype); pushdecl (var); @@ -1645,7 +1689,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) } tree ceq = contextual_conv_bool (eq, complain); info.check (ceq); - if (info.defining) + if (defining) { finish_if_stmt_cond (ceq, if_); finish_then_clause (if_); @@ -1658,7 +1702,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) finish_for_stmt (TREE_VALUE (loop_index)); } } - if (info.defining) + if (defining) { tree val; if (code == EQ_EXPR) @@ -1679,7 +1723,7 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) NULL_TREE, NULL, complain); comp = contextual_conv_bool (comp, complain); info.check (comp); - if (info.defining) + if (defining) { tree neg = build1 (TRUTH_NOT_EXPR, boolean_type_node, comp); finish_return_stmt (neg); @@ -1692,12 +1736,12 @@ build_comparison_op (tree fndecl, tsubst_flags_t complain) tree comp2 = build_new_op (info.loc, code, flags, comp, integer_zero_node, NULL_TREE, NULL, complain); info.check (comp2); - if (info.defining) + if (defining) finish_return_stmt (comp2); } out: - if (info.defining) + if (defining) finish_compound_stmt (compound_stmt); else --cp_unevaluated_operand; @@ -1776,7 +1820,7 @@ synthesize_method (tree fndecl) else if (sfk == sfk_comparison) { /* Pass tf_none so the function is just deleted if there's a problem. */ - build_comparison_op (fndecl, tf_none); + build_comparison_op (fndecl, true, tf_none); need_body = false; } @@ -1810,6 +1854,32 @@ synthesize_method (tree fndecl) fndecl); } +/* Like synthesize_method, but don't actually synthesize defaulted comparison + methods if their class is still incomplete. Just deduce the return + type in that case. */ + +void +maybe_synthesize_method (tree fndecl) +{ + if (special_function_p (fndecl) == sfk_comparison) + { + tree lhs = DECL_ARGUMENTS (fndecl); + if (is_this_parameter (lhs)) + lhs = cp_build_fold_indirect_ref (lhs); + else + lhs = convert_from_reference (lhs); + tree ctype = TYPE_MAIN_VARIANT (TREE_TYPE (lhs)); + if (!COMPLETE_TYPE_P (ctype)) + { + push_deferring_access_checks (dk_no_deferred); + build_comparison_op (fndecl, false, tf_none); + pop_deferring_access_checks (); + return; + } + } + return synthesize_method (fndecl); +} + /* Build a reference to type TYPE with cv-quals QUALS, which is an rvalue if RVALUE is true. */ @@ -2090,8 +2160,10 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) tree expr; if (code == MODIFY_EXPR) expr = assignable_expr (to, from); - else if (trivial && from && TREE_CHAIN (from)) + else if (trivial && from && TREE_CHAIN (from) + && cxx_dialect < cxx20) return error_mark_node; // only 0- and 1-argument ctors can be trivial + // before C++20 aggregate paren init else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to)) return error_mark_node; // can't construct an array of unknown bound else @@ -2747,7 +2819,7 @@ maybe_explain_implicit_delete (tree decl) inform (DECL_SOURCE_LOCATION (decl), "%q#D is implicitly deleted because the default " "definition would be ill-formed:", decl); - build_comparison_op (decl, tf_warning_or_error); + build_comparison_op (decl, false, tf_warning_or_error); } else if (!informed) { @@ -2808,7 +2880,7 @@ explain_implicit_non_constexpr (tree decl) if (sfk == sfk_comparison) { DECL_DECLARED_CONSTEXPR_P (decl) = true; - build_comparison_op (decl, tf_warning_or_error); + build_comparison_op (decl, false, tf_warning_or_error); DECL_DECLARED_CONSTEXPR_P (decl) = false; } else diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ddee8b3..c414a10 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3375,7 +3375,10 @@ set_decl_context_in_fn (tree ctx, tree decl) void push_local_extern_decl_alias (tree decl) { - if (dependent_type_p (TREE_TYPE (decl))) + if (dependent_type_p (TREE_TYPE (decl)) + || (processing_template_decl + && VAR_P (decl) + && CP_DECL_THREAD_LOCAL_P (decl))) return; /* EH specs were not part of the function type prior to c++17, but we still can't go pushing dependent eh specs into the namespace. */ @@ -3471,6 +3474,8 @@ push_local_extern_decl_alias (tree decl) push_nested_namespace (ns); alias = do_pushdecl (alias, /* hiding= */true); pop_nested_namespace (ns); + if (VAR_P (decl) && CP_DECL_THREAD_LOCAL_P (decl)) + set_decl_tls_model (alias, DECL_TLS_MODEL (decl)); } } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 62908da..d285a45 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1051,8 +1051,17 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) case RID_FLOAT: case RID_DOUBLE: case RID_VOID: + /* CV qualifiers. */ + case RID_CONST: + case RID_VOLATILE: + /* Function specifiers. */ + case RID_EXPLICIT: + case RID_VIRTUAL: + /* friend/typdef/inline specifiers. */ + case RID_FRIEND: + case RID_TYPEDEF: + case RID_INLINE: /* GNU extensions. */ - case RID_ATTRIBUTE: case RID_TYPEOF: /* C++11 extensions. */ case RID_DECLTYPE: @@ -10823,6 +10832,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) return error_mark_node; type2 = tree_cons (NULL_TREE, elt, type2); } + type2 = nreverse (type2); } location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; @@ -11456,8 +11466,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* In the decl-specifier-seq of the lambda-declarator, each decl-specifier shall either be mutable or constexpr. */ int declares_class_or_enum; - if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer) - && !cp_next_tokens_can_be_gnu_attribute_p (parser)) + if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)) cp_parser_decl_specifier_seq (parser, CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR, &lambda_specs, &declares_class_or_enum); @@ -14167,9 +14176,11 @@ cp_parser_jump_statement (cp_parser* parser) case RID_GOTO: if (parser->in_function_body - && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && cxx_dialect < cxx23) { - error ("%<goto%> in %<constexpr%> function"); + error ("%<goto%> in %<constexpr%> function only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); cp_function_chain->invalid_constexpr = true; } @@ -28628,7 +28639,16 @@ cp_parser_omp_directive_args (cp_parser *parser, tree attribute) TREE_VALUE (attribute) = NULL_TREE; return; } - for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 2; n; --n) + size_t n = cp_parser_skip_balanced_tokens (parser, 1); + if (n == 1) + { + cp_lexer_consume_token (parser->lexer); + error_at (first->location, "expected attribute argument as balanced " + "token sequence"); + TREE_VALUE (attribute) = NULL_TREE; + return; + } + for (n = n - 2; n; --n) cp_lexer_consume_token (parser->lexer); cp_token *last = cp_lexer_peek_token (parser->lexer); cp_lexer_consume_token (parser->lexer); @@ -30825,23 +30845,22 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, /* A parameter declaration begins with a decl-specifier, which is either the "attribute" keyword, a storage class specifier, or (usually) a type-specifier. */ - && (!cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer) - /* GNU attributes can actually appear both at the start of - a parameter and parenthesized declarator. - S (__attribute__((unused)) int); - is a constructor, but - S (__attribute__((unused)) foo) (int); - is a function declaration. */ - || (cp_parser_allow_gnu_extensions_p (parser) - && cp_next_tokens_can_be_gnu_attribute_p (parser))) - /* A parameter declaration can also begin with [[attribute]]. */ + && !cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer) + /* GNU attributes can actually appear both at the start of + a parameter and parenthesized declarator. + S (__attribute__((unused)) int); + is a constructor, but + S (__attribute__((unused)) foo) (int); + is a function declaration. [[attribute]] can appear in the + first form too, but not in the second form. */ && !cp_next_tokens_can_be_std_attribute_p (parser)) { tree type; tree pushed_scope = NULL_TREE; unsigned saved_num_template_parameter_lists; - if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + if (cp_parser_allow_gnu_extensions_p (parser) + && cp_next_tokens_can_be_gnu_attribute_p (parser)) { unsigned int n = cp_parser_skip_gnu_attributes_opt (parser, 1); while (--n) @@ -37718,6 +37737,7 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) tree c, id; const char *p; bool unconstrained = false; + bool reproducible = false; matching_parens parens; if (!parens.require_open (parser)) @@ -37730,7 +37750,9 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) p = IDENTIFIER_POINTER (id); if (strcmp (p, "unconstrained") == 0) unconstrained = true; - else if (strcmp (p, "reproducible") != 0) + else if (strcmp (p, "reproducible") == 0) + reproducible = true; + else { cp_parser_error (parser, "expected %<reproducible%> or " "%<unconstrained%>"); @@ -37761,6 +37783,7 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order", location); c = build_omp_clause (location, OMP_CLAUSE_ORDER); OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; OMP_CLAUSE_CHAIN (c) = list; return c; @@ -38337,13 +38360,21 @@ cp_parser_omp_clause_aligned (cp_parser *parser, tree list) /* OpenMP 5.0: allocate ( variable-list ) - allocate ( expression : variable-list ) */ + allocate ( expression : variable-list ) + + OpenMP 5.1: + allocate ( allocator-modifier : variable-list ) + allocate ( allocator-modifier , allocator-modifier : variable-list ) + + allocator-modifier: + allocator ( expression ) + align ( expression ) */ static tree cp_parser_omp_clause_allocate (cp_parser *parser, tree list) { - tree nlist, c, allocator = NULL_TREE; - bool colon; + tree nlist, c, allocator = NULL_TREE, align = NULL_TREE; + bool colon, has_modifiers = false; matching_parens parens; if (!parens.require_open (parser)) @@ -38352,7 +38383,51 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list) cp_parser_parse_tentatively (parser); bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; parser->colon_corrects_to_scope_p = false; - allocator = cp_parser_assignment_expression (parser); + for (int mod = 0; mod < 2; mod++) + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (strcmp (p, "allocator") != 0 && strcmp (p, "align") != 0) + break; + cp_lexer_consume_token (parser->lexer); + matching_parens parens2; + if (!parens2.require_open (parser)) + break; + if (strcmp (p, "allocator") == 0) + { + if (allocator != NULL_TREE) + break; + allocator = cp_parser_assignment_expression (parser); + } + else + { + if (align != NULL_TREE) + break; + align = cp_parser_assignment_expression (parser); + } + if (!parens2.require_close (parser)) + break; + if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + has_modifiers = true; + break; + } + if (mod != 0 || cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + else + break; + if (!has_modifiers) + { + cp_parser_abort_tentative_parse (parser); + align = NULL_TREE; + allocator = NULL_TREE; + cp_parser_parse_tentatively (parser); + allocator = cp_parser_assignment_expression (parser); + } parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { @@ -38360,18 +38435,25 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list) cp_lexer_consume_token (parser->lexer); if (allocator == error_mark_node) allocator = NULL_TREE; + if (align == error_mark_node) + align = NULL_TREE; } else { cp_parser_abort_tentative_parse (parser); allocator = NULL_TREE; + align = NULL_TREE; } nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALLOCATE, list, &colon); - for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + if (allocator || align) + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; + } return nlist; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4d42899..009fe6d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6760,8 +6760,15 @@ has_value_dependent_address (tree op) if (DECL_P (op)) { tree ctx = CP_DECL_CONTEXT (op); + if (TYPE_P (ctx) && dependent_type_p (ctx)) return true; + + if (VAR_P (op) + && TREE_STATIC (op) + && TREE_CODE (ctx) == FUNCTION_DECL + && type_dependent_expression_p (ctx)) + return true; } return false; @@ -7994,12 +8001,12 @@ coerce_template_template_parms (tree parm_parms, /* So coerce P's args to apply to A's parms, and then deduce between A's args and the converted args. If that succeeds, A is at least as specialized as P, so they match.*/ + processing_template_decl_sentinel ptds (/*reset*/false); + ++processing_template_decl; tree pargs = template_parms_level_to_args (parm_parms); pargs = add_outermost_template_args (outer_args, pargs); - ++processing_template_decl; pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none, /*require_all*/true, /*use_default*/true); - --processing_template_decl; if (pargs != error_mark_node) { tree targs = make_tree_vec (nargs); @@ -8223,8 +8230,10 @@ is_compatible_template_arg (tree parm, tree arg) { tree aparms = DECL_INNERMOST_TEMPLATE_PARMS (arg); new_args = template_parms_level_to_args (aparms); + ++processing_template_decl; parm_cons = tsubst_constraint_info (parm_cons, new_args, tf_none, NULL_TREE); + --processing_template_decl; if (parm_cons == error_mark_node) return false; } @@ -8521,6 +8530,10 @@ convert_template_argument (tree parm, else t = tsubst (t, args, complain, in_decl); + /* Perform array-to-pointer and function-to-pointer conversion + as per [temp.param]/10. */ + t = type_decays_to (t); + if (invalid_nontype_parm_type_p (t, complain)) return error_mark_node; @@ -17489,6 +17502,13 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, break; case OMP_CLAUSE_GANG: case OMP_CLAUSE_ALIGNED: + OMP_CLAUSE_DECL (nc) + = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, + in_decl, NULL); + OMP_CLAUSE_OPERAND (nc, 1) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; case OMP_CLAUSE_ALLOCATE: OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, @@ -17496,6 +17516,9 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, OMP_CLAUSE_OPERAND (nc, 1) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_OPERAND (nc, 2) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 2), args, complain, + in_decl, /*integral_constant_expression_p=*/false); break; case OMP_CLAUSE_LINEAR: OMP_CLAUSE_DECL (nc) @@ -25756,7 +25779,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) return true; ++function_depth; - synthesize_method (fn); + maybe_synthesize_method (fn); --function_depth; return !DECL_MAYBE_DELETED (fn); } @@ -27237,7 +27260,8 @@ value_dependent_expression_p (tree expression) } case TEMPLATE_ID_EXPR: - return concept_definition_p (TREE_OPERAND (expression, 0)); + return concept_definition_p (TREE_OPERAND (expression, 0)) + && any_dependent_template_arguments_p (TREE_OPERAND (expression, 1)); case CONSTRUCTOR: { @@ -27644,18 +27668,6 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, case REQUIRES_EXPR: return *tp; - case CALL_EXPR: - /* Treat concept checks as dependent. */ - if (concept_check_p (*tp)) - return *tp; - break; - - case TEMPLATE_ID_EXPR: - /* Treat concept checks as dependent. */ - if (concept_check_p (*tp)) - return *tp; - break; - case CONSTRUCTOR: if (CONSTRUCTOR_IS_DEPENDENT (*tp)) return *tp; @@ -27813,6 +27825,20 @@ dependent_template_arg_p (tree arg) return value_dependent_expression_p (arg); } +/* Identify any expressions that use function parms. */ + +static tree +find_parm_usage_r (tree *tp, int *walk_subtrees, void*) +{ + tree t = *tp; + if (TREE_CODE (t) == PARM_DECL) + { + *walk_subtrees = 0; + return t; + } + return NULL_TREE; +} + /* Returns true if ARGS (a collection of template arguments) contains any types that require structural equality testing. */ @@ -27857,6 +27883,13 @@ any_template_arguments_need_structural_equality_p (tree args) else if (!TYPE_P (arg) && TREE_TYPE (arg) && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg))) return true; + /* Checking current_function_decl because this structural + comparison is only necessary for redeclaration. */ + else if (!current_function_decl + && dependent_template_arg_p (arg) + && (cp_walk_tree_without_duplicates + (&arg, find_parm_usage_r, NULL))) + return true; } } } @@ -28734,7 +28767,7 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, const int depth = TMPL_ARGS_DEPTH (tsubst_args); tree ttargs = make_tree_vec (depth + 1); for (int i = 0; i < depth; ++i) - TREE_VEC_ELT (ttargs, i) = TREE_VEC_ELT (tsubst_args, i); + TREE_VEC_ELT (ttargs, i) = TMPL_ARGS_LEVEL (tsubst_args, i + 1); TREE_VEC_ELT (ttargs, depth) = template_parms_level_to_args (ttparms); // Substitute ttargs into ttparms to fix references to @@ -28747,8 +28780,17 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, ttparms = tsubst_template_parms_level (ttparms, ttargs, complain); // Finally, tack the adjusted parms onto tparms. - ttparms = tree_cons (size_int (depth), ttparms, - current_template_parms); + ttparms = tree_cons (size_int (level + 1), ttparms, + copy_node (current_template_parms)); + // As with all template template parms, the parameter list captured + // by this template template parm that corresponds to its own level + // should be empty. This avoids infinite recursion when structurally + // comparing two such rewritten template template parms (PR102479). + gcc_assert (!TREE_VEC_LENGTH + (TREE_VALUE (TREE_CHAIN (DECL_TEMPLATE_PARMS (olddecl))))); + gcc_assert (TMPL_PARMS_DEPTH (TREE_CHAIN (ttparms)) == level); + TREE_VALUE (TREE_CHAIN (ttparms)) = make_tree_vec (0); + // All done. DECL_TEMPLATE_PARMS (newdecl) = ttparms; } } @@ -29246,6 +29288,11 @@ alias_ctad_tweaks (tree tmpl, tree uguides) ++ndlen; tree gtparms = make_tree_vec (natparms + ndlen); + /* Set current_template_parms as in build_deduction_guide. */ + auto ctp = make_temp_override (current_template_parms); + current_template_parms = copy_node (DECL_TEMPLATE_PARMS (tmpl)); + TREE_VALUE (current_template_parms) = gtparms; + /* First copy over the parms of A. */ for (j = 0; j < natparms; ++j) TREE_VEC_ELT (gtparms, j) = TREE_VEC_ELT (atparms, j); diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index 7f140f5..1dcd764 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -51,6 +51,7 @@ cxx_print_decl (FILE *file, tree node, int indent) } else if (TREE_CODE (node) == TEMPLATE_DECL) { + print_node (file, "result", DECL_TEMPLATE_RESULT (node), indent + 4); print_node (file, "parms", DECL_TEMPLATE_PARMS (node), indent + 4); indent_to (file, indent + 3); fprintf (file, " full-name \"%s\"", @@ -115,13 +116,8 @@ cxx_print_decl (FILE *file, tree node, int indent) if (VAR_OR_FUNCTION_DECL_P (node) && DECL_TEMPLATE_INFO (node)) - { - if (need_indent) - indent_to (file, indent + 3); - fprintf (file, " template-info %p", - (void *) DECL_TEMPLATE_INFO (node)); - need_indent = false; - } + print_node (file, "template-info", DECL_TEMPLATE_INFO (node), + indent + 4); } void diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 35a7b9f..0d8e5fd 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7527,7 +7527,44 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bitmap_set_bit (&aligned_head, DECL_UID (t)); allocate_seen = true; } - tree allocator; + tree allocator, align; + align = OMP_CLAUSE_ALLOCATE_ALIGN (c); + if (error_operand_p (align)) + { + remove = true; + break; + } + if (align) + { + if (!type_dependent_expression_p (align) + && !INTEGRAL_TYPE_P (TREE_TYPE (align))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<allocate%> clause %<align%> modifier " + "argument needs to be positive constant " + "power of two integer expression"); + remove = true; + } + else + { + align = mark_rvalue_use (align); + if (!processing_template_decl) + { + align = maybe_constant_value (align); + if (TREE_CODE (align) != INTEGER_CST + || !tree_fits_uhwi_p (align) + || !integer_pow2p (align)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<allocate%> clause %<align%> modifier " + "argument needs to be positive constant " + "power of two integer expression"); + remove = true; + } + } + } + OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; + } allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); if (error_operand_p (allocator)) { @@ -7552,6 +7589,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) "type %qT rather than %<omp_allocator_handle_t%>", TREE_TYPE (allocator)); remove = true; + break; } else { diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 3c62dd7..32ddf83 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1403,11 +1403,18 @@ cp_build_qualified_type_real (tree type, /* A reference or method type shall not be cv-qualified. [dcl.ref], [dcl.fct]. This used to be an error, but as of DR 295 (in CD1) we always ignore extra cv-quals on functions. */ + + /* [dcl.ref/1] Cv-qualified references are ill-formed except when + the cv-qualifiers are introduced through the use of a typedef-name + ([dcl.typedef], [temp.param]) or decltype-specifier + ([dcl.type.decltype]),in which case the cv-qualifiers are + ignored. */ if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE) && (TYPE_REF_P (type) || FUNC_OR_METHOD_TYPE_P (type))) { - if (TYPE_REF_P (type)) + if (TYPE_REF_P (type) + && (!typedef_variant_p (type) || FUNC_OR_METHOD_TYPE_P (type))) bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); } @@ -1492,9 +1499,9 @@ apply_identity_attributes (tree result, tree attribs, bool *remove_attributes) p = &TREE_CHAIN (*p); } } - else if (first_ident) + else if (first_ident && first_ident != error_mark_node) { - for (tree a2 = first_ident; a2; a2 = TREE_CHAIN (a2)) + for (tree a2 = first_ident; a2 != a; a2 = TREE_CHAIN (a2)) { *p = tree_cons (TREE_PURPOSE (a2), TREE_VALUE (a2), NULL_TREE); p = &TREE_CHAIN (*p); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index a2398db..ab0f9da 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4603,25 +4603,93 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain) || warning_suppressed_p (op, OPT_Waddress)) return; + if (TREE_CODE (op) == NON_DEPENDENT_EXPR) + op = TREE_OPERAND (op, 0); + tree cop = fold_for_warn (op); - if (TREE_CODE (cop) == ADDR_EXPR - && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0)) - && !warning_suppressed_p (cop, OPT_Waddress)) - warning_at (location, OPT_Waddress, "the address of %qD will never " - "be NULL", TREE_OPERAND (cop, 0)); + if (TREE_CODE (cop) == NON_LVALUE_EXPR) + /* Unwrap the expression for C++ 98. */ + cop = TREE_OPERAND (cop, 0); - if (CONVERT_EXPR_P (op) + if (TREE_CODE (cop) == PTRMEM_CST) + { + /* The address of a nonstatic data member is never null. */ + warning_at (location, OPT_Waddress, + "the address %qE will never be NULL", + cop); + return; + } + + if (TREE_CODE (cop) == NOP_EXPR) + { + /* Allow casts to intptr_t to suppress the warning. */ + tree type = TREE_TYPE (cop); + if (TREE_CODE (type) == INTEGER_TYPE) + return; + + STRIP_NOPS (cop); + } + + bool warned = false; + if (TREE_CODE (cop) == ADDR_EXPR) + { + cop = TREE_OPERAND (cop, 0); + + /* Set to true in the loop below if OP dereferences its operand. + In such a case the ultimate target need not be a decl for + the null [in]equality test to be necessarily constant. */ + bool deref = false; + + /* Get the outermost array or object, or member. */ + while (handled_component_p (cop)) + { + if (TREE_CODE (cop) == COMPONENT_REF) + { + /* Get the member (its address is never null). */ + cop = TREE_OPERAND (cop, 1); + break; + } + + /* Get the outer array/object to refer to in the warning. */ + cop = TREE_OPERAND (cop, 0); + deref = true; + } + + if ((!deref && !decl_with_nonnull_addr_p (cop)) + || from_macro_expansion_at (location) + || warning_suppressed_p (cop, OPT_Waddress)) + return; + + warned = warning_at (location, OPT_Waddress, + "the address of %qD will never be NULL", cop); + op = cop; + } + else if (TREE_CODE (cop) == POINTER_PLUS_EXPR) + { + /* Adding zero to the null pointer is well-defined in C++. When + the offset is unknown (i.e., not a constant) warn anyway since + it's less likely that the pointer operand is null than not. */ + tree off = TREE_OPERAND (cop, 1); + if (!integer_zerop (off) + && !warning_suppressed_p (cop, OPT_Waddress)) + warning_at (location, OPT_Waddress, "comparing the result of pointer " + "addition %qE and NULL", cop); + return; + } + else if (CONVERT_EXPR_P (op) && TYPE_REF_P (TREE_TYPE (TREE_OPERAND (op, 0)))) { - tree inner_op = op; - STRIP_NOPS (inner_op); + STRIP_NOPS (op); - if (DECL_P (inner_op)) - warning_at (location, OPT_Waddress, - "the compiler can assume that the address of " - "%qD will never be NULL", inner_op); + if (DECL_P (op)) + warned = warning_at (location, OPT_Waddress, + "the compiler can assume that the address of " + "%qD will never be NULL", op); } + + if (warned && DECL_P (op)) + inform (DECL_SOURCE_LOCATION (op), "%qD declared here", op); } /* Warn about [expr.arith.conv]/2: If one operand is of enumeration type and @@ -5289,6 +5357,11 @@ cp_build_binary_op (const op_location_t &location, warning_at (location, OPT_Waddress, "comparison with string literal results in " "unspecified behavior"); + else if (warn_array_compare + && TREE_CODE (TREE_TYPE (orig_op0)) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (orig_op1)) == ARRAY_TYPE) + do_warn_array_compare (location, code, stripped_orig_op0, + stripped_orig_op1); } build_type = boolean_type_node; @@ -5411,6 +5484,8 @@ cp_build_binary_op (const op_location_t &location, op1 = cp_convert (TREE_TYPE (op0), op1, complain); } result_type = TREE_TYPE (op0); + + warn_for_null_address (location, orig_op0, complain); } else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (orig_op0)) return cp_build_binary_op (location, code, op1, op0, complain); @@ -5559,6 +5634,14 @@ cp_build_binary_op (const op_location_t &location, "comparison with string literal results " "in unspecified behavior"); } + else if (warn_array_compare + && TREE_CODE (TREE_TYPE (orig_op0)) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (orig_op1)) == ARRAY_TYPE + && code != SPACESHIP_EXPR + && (complain & tf_warning)) + do_warn_array_compare (location, code, + tree_strip_any_location_wrapper (orig_op0), + tree_strip_any_location_wrapper (orig_op1)); if (gnu_vector_type_p (type0) && gnu_vector_type_p (type1)) { @@ -6038,7 +6121,9 @@ cp_build_binary_op (const op_location_t &location, } if (sanitize_flags_p ((SANITIZE_SHIFT - | SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE)) + | SANITIZE_DIVIDE + | SANITIZE_FLOAT_DIVIDE + | SANITIZE_SI_OVERFLOW)) && current_function_decl != NULL_TREE && !processing_template_decl && (doing_div_or_mod || doing_shift)) @@ -6050,7 +6135,9 @@ cp_build_binary_op (const op_location_t &location, op1 = fold_non_dependent_expr (op1, complain); tree instrument_expr1 = NULL_TREE; if (doing_div_or_mod - && sanitize_flags_p (SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE)) + && sanitize_flags_p (SANITIZE_DIVIDE + | SANITIZE_FLOAT_DIVIDE + | SANITIZE_SI_OVERFLOW)) { /* For diagnostics we want to use the promoted types without shorten_binary_op. So convert the arguments to the |