aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-10-07 15:28:36 -0700
committerIan Lance Taylor <iant@golang.org>2021-10-07 15:28:36 -0700
commit0b6b70a0733672600644c8df96942cda5bf86d3d (patch)
tree9a1fbd7f782c54df55ab225ed1be057e3f3b0b8a /gcc/cp
parenta5b5cabc91c38710adbe5c8a2b53882abe994441 (diff)
parentfba228e259dd5112851527f2dbb62c5601100985 (diff)
downloadgcc-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/ChangeLog234
-rw-r--r--gcc/cp/class.c13
-rw-r--r--gcc/cp/constexpr.c66
-rw-r--r--gcc/cp/coroutines.cc80
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c9
-rw-r--r--gcc/cp/init.c11
-rw-r--r--gcc/cp/method.c244
-rw-r--r--gcc/cp/name-lookup.c7
-rw-r--r--gcc/cp/parser.c130
-rw-r--r--gcc/cp/pt.c85
-rw-r--r--gcc/cp/ptree.c10
-rw-r--r--gcc/cp/semantics.c40
-rw-r--r--gcc/cp/tree.c13
-rw-r--r--gcc/cp/typeck.c115
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