summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog116
-rw-r--r--gcc/cp/call.c179
-rw-r--r--gcc/cp/class.c13
-rw-r--r--gcc/cp/constexpr.c132
-rw-r--r--gcc/cp/cp-tree.h13
-rw-r--r--gcc/cp/decl.c52
-rw-r--r--gcc/cp/decl2.c10
-rw-r--r--gcc/cp/error.c21
-rw-r--r--gcc/cp/init.c67
-rw-r--r--gcc/cp/mangle.c4
-rw-r--r--gcc/cp/name-lookup.c22
-rw-r--r--gcc/cp/parser.c61
-rw-r--r--gcc/cp/pt.c2
-rw-r--r--gcc/cp/semantics.c2
-rw-r--r--gcc/cp/tree.c24
-rw-r--r--gcc/cp/typeck.c55
16 files changed, 582 insertions, 191 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c553796d7bf..9d74bdbb8ba 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,115 @@
+2016-09-16 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77482
+ * error.c (dump_simple_decl): Only check DECL_DECLARED_CONCEPT_P
+ if DECL_LANG_SPECIFIC is non-NULL. Fix up formatting.
+
+ PR c++/77338
+ * constexpr.c (cxx_eval_constant_expression) <case PARM_DECL>: Only
+ call is_really_empty_class on complete types.
+
+ PR c++/77375
+ * class.c (check_bases): Set CLASSTYPE_HAS_MUTABLE if any
+ TYPE_HAS_MUTABLE_P for any bases.
+
+2016-09-16 Jason Merrill <jason@redhat.com>
+
+ * class.c (check_bases, set_one_vmethod_tm_attributes): Use
+ least_bit_hwi.
+ * decl.c (cxx_init_decl_processing): Use pow2p_hwi.
+ * parser.c (cp_parser_cilk_simd_vectorlength): Use pow2p_hwi.
+
+2016-09-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77549
+ * name-lookup.c (consider_binding_level): Look through TREE_LIST
+ and OVERLOAD.
+
+2016-09-14 Marek Polacek <polacek@redhat.com>
+
+ * typeck.c (cp_build_unary_op): Diagnose incrementing boolean
+ expressions. Tweak an error message.
+
+2016-09-14 Marek Polacek <polacek@redhat.com>
+
+ * cp-tree.h (cp_build_unary_op): Change nonconvert parameter type to
+ bool.
+ * decl2.c (one_static_initialization_or_destruction): Use true instead
+ of 1.
+ * init.c (build_vec_init): Use false instead of 0.
+ * pt.c (tsubst_copy_and_build): Likewise.
+ * semantics.c (simplify_loop_decl_cond): Likewise.
+ * typeck.c (rationalize_conditional_expr): Likewise.
+ (cp_build_binary_op): Use true instead of 1.
+ (cp_build_unary_op): Change nonconvert parameter type to bool. Use true
+ instead of 1.
+ (build_unary_op): Change nonconvert parameter type to bool.
+ (unary_complex_lvalue): Use false instead of 0.
+
+2016-09-13 Jakub Jelinek <jakub@redhat.com>
+
+ Implement P0028R4, C++17 using attribute namespaces without repetition
+ * parser.c (cp_parser_std_attribute): Add ATTR_NS argument. Diagnose
+ non-NULL ATTR_NS with scoped attribute token. Handle non-NULL
+ ATTR_NS with non-scoped attribute tokens. Allow named ops in
+ identifier after ::.
+ (cp_parser_std_attribute_list): Add ATTR_NS argument, pass it down
+ to cp_parser_std_attribute calls.
+ (cp_parser_std_attribute_spec): Parse optional C++17
+ attribute-using-prefix, adjust grammar in function comment.
+
+ PR c++/77553
+ * constexpr.c (cxx_fold_pointer_plus_expression): New function.
+ (cxx_eval_binary_expression): Use it for POINTER_PLUS_EXPR.
+ (cxx_eval_pointer_plus_expression): Remove.
+ (cxx_eval_constant_expression) <case POINTER_PLUS_EXPR>: Don't
+ call cxx_eval_pointer_plus_expression.
+
+2016-09-13 David Malcolm <dmalcolm@redhat.com>
+
+ * parser.c (cp_parser_class_specifier_1): Update for renaming of
+ add_fixit_insert to add_fixit_insert_before.
+ (cp_parser_class_head): Likewise.
+
+2016-09-12 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR c++/77496
+ * call.c (build_conditional_expr_1): Call warn_for_omitted_condop.
+ * class.c (instantiate_type): Look through the SAVE_EXPR.
+
+2016-09-09 Jason Merrill <jason@redhat.com>
+
+ Implement P0035R4, C++17 new of over-aligned types.
+ * cp-tree.h (enum cp_tree_index): Add CPTI_ALIGN_TYPE.
+ (align_type_node): New macro.
+ * call.c (build_operator_new_call): Handle C++17 aligned new.
+ (second_parm_is_size_t, build_op_delete_call): Likewise.
+ (non_placement_deallocation_fn_p): Likewise. Rename to
+ usual_deallocation_fn_p.
+ (aligned_allocation_fn_p, aligned_deallocation_fn_p): New.
+ * decl.c (cxx_init_decl_processing): Add aligned new support.
+ * init.c (type_has_new_extended_alignment): New.
+ (build_new_1): Handle aligned new.
+ * tree.c (vec_copy_and_insert): New.
+
+2016-09-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/77396
+ * decl2.c (do_static_initialization_or_destruction): Only
+ call asan_dynamic_init_call if INITP is true.
+
+2016-09-01 Martin Sebor <msebor@redhat.com>
+
+ * mangle.c: Increase buffer size to guarantee it fits the output
+ of the formatted function regardless of its arguments.
+
+2016-09-01 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * error.c (dump_type): Fix falls through comment.
+ (dump_decl): Likewise.
+ (dump_expr): Likewise.
+
2016-08-30 David Malcolm <dmalcolm@redhat.com>
* parser.c (cp_parser_enclosed_template_argument_list): Add fix-it
@@ -78,7 +190,7 @@
* semantics.c (finish_omp_clauses): Add FALLTHRU.
* tree.c (lvalue_kind): Likewise.
-2016-08-12 Alexandre Oliva <aoliva@redhat.com>
+2016-08-12 Alexandre Oliva <aoliva@redhat.com>
PR debug/63240
* cp-objcp-common.c (cp_function_decl_defaulted): New.
@@ -287,7 +399,7 @@
* cp-gimplify.c (cp_fully_fold): Only maybe_constant_value in
C++11 and up.
-2016-07-30 Martin Sebor <msebor@redhat.com>
+2016-07-30 Martin Sebor <msebor@redhat.com>
PR c++/60760
PR c++/71091
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 024519d3601..393aab91bee 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4211,13 +4211,14 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
tree
build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
- tree *size, tree *cookie_size, tree size_check,
+ tree *size, tree *cookie_size,
+ tree align_arg, tree size_check,
tree *fn, tsubst_flags_t complain)
{
tree original_size = *size;
tree fns;
struct z_candidate *candidates;
- struct z_candidate *cand;
+ struct z_candidate *cand = NULL;
bool any_viable_p;
if (fn)
@@ -4247,9 +4248,20 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
we disregard block-scope declarations of "operator new". */
fns = lookup_function_nonclass (fnname, *args, /*block_p=*/false);
+ if (align_arg)
+ {
+ vec<tree, va_gc>* align_args
+ = vec_copy_and_insert (*args, align_arg, 1);
+ cand = perform_overload_resolution (fns, align_args, &candidates,
+ &any_viable_p, tf_none);
+ /* If no aligned allocation function matches, try again without the
+ alignment. */
+ }
+
/* Figure out what function is being called. */
- cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
- complain);
+ if (!cand)
+ cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
+ complain);
/* If no suitable function could be found, issue an error message
and give up. */
@@ -4653,9 +4665,12 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
if (!arg2)
{
if (complain & tf_error)
- pedwarn (loc, OPT_Wpedantic,
+ pedwarn (loc, OPT_Wpedantic,
"ISO C++ forbids omitting the middle term of a ?: expression");
+ if ((complain & tf_warning) && !truth_value_p (TREE_CODE (arg1)))
+ warn_for_omitted_condop (loc, arg1);
+
/* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */
if (lvalue_p (arg1))
arg2 = arg1 = cp_stabilize_reference (arg1);
@@ -5945,16 +5960,65 @@ static bool
second_parm_is_size_t (tree fn)
{
tree t = FUNCTION_ARG_CHAIN (fn);
- return (t
- && same_type_p (TREE_VALUE (t), size_type_node)
- && TREE_CHAIN (t) == void_list_node);
+ if (!t || !same_type_p (TREE_VALUE (t), size_type_node))
+ return false;
+ t = TREE_CHAIN (t);
+ if (t == void_list_node)
+ return true;
+ if (aligned_new_threshhold && t
+ && same_type_p (TREE_VALUE (t), align_type_node)
+ && TREE_CHAIN (t) == void_list_node)
+ return true;
+ return false;
+}
+
+/* True if T, an allocation function, has std::align_val_t as its second
+ argument. */
+
+bool
+aligned_allocation_fn_p (tree t)
+{
+ if (!aligned_new_threshhold)
+ return false;
+
+ tree a = FUNCTION_ARG_CHAIN (t);
+ return (a && same_type_p (TREE_VALUE (a), align_type_node));
+}
+
+/* Returns true iff T, an element of an OVERLOAD chain, is a usual deallocation
+ function (3.7.4.2 [basic.stc.dynamic.deallocation]) with a parameter of
+ std::align_val_t. */
+
+static bool
+aligned_deallocation_fn_p (tree t)
+{
+ if (!aligned_new_threshhold)
+ return false;
+
+ /* A template instance is never a usual deallocation function,
+ regardless of its signature. */
+ if (TREE_CODE (t) == TEMPLATE_DECL
+ || primary_template_instantiation_p (t))
+ return false;
+
+ tree a = FUNCTION_ARG_CHAIN (t);
+ if (same_type_p (TREE_VALUE (a), align_type_node)
+ && TREE_CHAIN (a) == void_list_node)
+ return true;
+ if (!same_type_p (TREE_VALUE (a), size_type_node))
+ return false;
+ a = TREE_CHAIN (a);
+ if (a && same_type_p (TREE_VALUE (a), align_type_node)
+ && TREE_CHAIN (a) == void_list_node)
+ return true;
+ return false;
}
/* Returns true iff T, an element of an OVERLOAD chain, is a usual
deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]). */
bool
-non_placement_deallocation_fn_p (tree t)
+usual_deallocation_fn_p (tree t)
{
/* A template instance is never a usual deallocation function,
regardless of its signature. */
@@ -5970,10 +6034,15 @@ non_placement_deallocation_fn_p (tree t)
of which has type std::size_t (18.2), then this function is a usual
deallocation function. */
bool global = DECL_NAMESPACE_SCOPE_P (t);
- if (FUNCTION_ARG_CHAIN (t) == void_list_node
+ tree chain = FUNCTION_ARG_CHAIN (t);
+ if (!chain)
+ return false;
+ if (chain == void_list_node
|| ((!global || flag_sized_deallocation)
&& second_parm_is_size_t (t)))
return true;
+ if (aligned_deallocation_fn_p (t))
+ return true;
return false;
}
@@ -6076,7 +6145,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
t; t = OVL_NEXT (t))
{
tree elt = OVL_CURRENT (t);
- if (non_placement_deallocation_fn_p (elt)
+ if (usual_deallocation_fn_p (elt)
&& FUNCTION_ARG_CHAIN (elt) == void_list_node)
goto ok;
}
@@ -6118,51 +6187,62 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
t; t = OVL_NEXT (t))
{
tree elt = OVL_CURRENT (t);
- if (non_placement_deallocation_fn_p (elt))
+ if (usual_deallocation_fn_p (elt))
{
- fn = elt;
- /* "If a class T has a member deallocation function named
- operator delete with exactly one parameter, then that
- function is a usual (non-placement) deallocation
- function. If class T does not declare such an operator
- delete but does declare a member deallocation function named
- operator delete with exactly two parameters, the second of
- which has type std::size_t (18.2), then this function is a
- usual deallocation function."
-
- So in a class (void*) beats (void*, size_t). */
- if (DECL_CLASS_SCOPE_P (fn))
+ if (!fn)
{
- if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
- break;
+ fn = elt;
+ continue;
}
- /* At global scope (in C++14 and above) the rules are different:
-
- If deallocation function lookup finds both a usual
- deallocation function with only a pointer parameter and a
- usual deallocation function with both a pointer parameter
- and a size parameter, the function to be called is selected
- as follows:
-
- * If the type is complete and if, for the second alternative
- (delete array) only, the operand is a pointer to a class
- type with a non-trivial destructor or a (possibly
- multi-dimensional) array thereof, the function with two
- parameters is selected.
-
- * Otherwise, it is unspecified which of the two deallocation
- functions is selected. */
+
+ /* -- If the type has new-extended alignment, a function with a
+ parameter of type std::align_val_t is preferred; otherwise a
+ function without such a parameter is preferred. If exactly one
+ preferred function is found, that function is selected and the
+ selection process terminates. If more than one preferred
+ function is found, all non-preferred functions are eliminated
+ from further consideration. */
+ if (aligned_new_threshhold)
+ {
+ bool want_align = type_has_new_extended_alignment (type);
+ bool fn_align = aligned_deallocation_fn_p (fn);
+ bool elt_align = aligned_deallocation_fn_p (elt);
+
+ if (elt_align != fn_align)
+ {
+ if (want_align == elt_align)
+ fn = elt;
+ continue;
+ }
+ }
+
+ /* -- If the deallocation functions have class scope, the one
+ without a parameter of type std::size_t is selected. */
+ bool want_size;
+ if (DECL_CLASS_SCOPE_P (fn))
+ want_size = false;
+
+ /* -- If the type is complete and if, for the second alternative
+ (delete array) only, the operand is a pointer to a class type
+ with a non-trivial destructor or a (possibly multi-dimensional)
+ array thereof, the function with a parameter of type std::size_t
+ is selected.
+
+ -- Otherwise, it is unspecified whether a deallocation function
+ with a parameter of type std::size_t is selected. */
else
{
- bool want_size = COMPLETE_TYPE_P (type);
+ want_size = COMPLETE_TYPE_P (type);
if (code == VEC_DELETE_EXPR
&& !TYPE_VEC_NEW_USES_COOKIE (type))
/* We need a cookie to determine the array size. */
want_size = false;
- bool have_size = (FUNCTION_ARG_CHAIN (fn) != void_list_node);
- if (want_size == have_size)
- break;
}
+ bool fn_size = second_parm_is_size_t (fn);
+ bool elt_size = second_parm_is_size_t (elt);
+ gcc_assert (fn_size != elt_size);
+ if (want_size == elt_size)
+ fn = elt;
}
}
@@ -6200,8 +6280,13 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
tree ret;
vec<tree, va_gc> *args = make_tree_vector ();
args->quick_push (addr);
- if (FUNCTION_ARG_CHAIN (fn) != void_list_node)
+ if (second_parm_is_size_t (fn))
args->quick_push (size);
+ if (aligned_deallocation_fn_p (fn))
+ {
+ tree al = build_int_cst (align_type_node, TYPE_ALIGN_UNIT (type));
+ args->quick_push (al);
+ }
ret = cp_build_function_call_vec (fn, &args, complain);
release_tree_vector (args);
return ret;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a4f3c6b6aba..7362c732646 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1796,6 +1796,8 @@ check_bases (tree t,
SET_CLASSTYPE_REF_FIELDS_NEED_INIT
(t, CLASSTYPE_REF_FIELDS_NEED_INIT (t)
| CLASSTYPE_REF_FIELDS_NEED_INIT (basetype));
+ if (TYPE_HAS_MUTABLE_P (basetype))
+ CLASSTYPE_HAS_MUTABLE (t) = 1;
/* A standard-layout class is a class that:
...
@@ -1843,7 +1845,7 @@ check_bases (tree t,
doesn't define its own, then the current class inherits one. */
if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t)))
{
- tree tm_attr = tm_mask_to_attr (seen_tm_mask & -seen_tm_mask);
+ tree tm_attr = tm_mask_to_attr (least_bit_hwi (seen_tm_mask));
TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t));
}
}
@@ -5074,7 +5076,7 @@ set_one_vmethod_tm_attributes (tree type, tree fndecl)
restrictive one. */
else if (tm_attr == NULL)
{
- apply_tm_attr (fndecl, tm_mask_to_attr (found & -found));
+ apply_tm_attr (fndecl, tm_mask_to_attr (least_bit_hwi (found)));
}
/* Otherwise validate that we're not weaker than a function
that is being overridden. */
@@ -8262,7 +8264,12 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t complain)
return error_mark_node;
}
- /* There only a few kinds of expressions that may have a type
+ /* If we instantiate a template, and it is a A ?: C expression
+ with omitted B, look through the SAVE_EXPR. */
+ if (TREE_CODE (rhs) == SAVE_EXPR)
+ rhs = TREE_OPERAND (rhs, 0);
+
+ /* There are only a few kinds of expressions that may have a type
dependent on overload resolution. */
gcc_assert (TREE_CODE (rhs) == ADDR_EXPR
|| TREE_CODE (rhs) == COMPONENT_REF
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 5d97a4be4f1..9308c548621 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1813,6 +1813,63 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
return r;
}
+/* Helper function for cxx_eval_binary_expression. Try to optimize
+ original POINTER_PLUS_EXPR T, LHS p+ RHS, return NULL_TREE if the
+ generic folding should be used. */
+
+static tree
+cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
+ tree lhs, tree rhs, bool *non_constant_p,
+ bool *overflow_p)
+{
+ STRIP_NOPS (lhs);
+ if (TREE_CODE (lhs) != ADDR_EXPR)
+ return NULL_TREE;
+
+ lhs = TREE_OPERAND (lhs, 0);
+
+ /* &A[i] p+ j => &A[i + j] */
+ if (TREE_CODE (lhs) == ARRAY_REF
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == INTEGER_CST
+ && TREE_CODE (rhs) == INTEGER_CST
+ && TYPE_SIZE_UNIT (TREE_TYPE (lhs))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (lhs))) == INTEGER_CST)
+ {
+ tree orig_type = TREE_TYPE (t);
+ location_t loc = EXPR_LOCATION (t);
+ tree type = TREE_TYPE (lhs);
+
+ t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1));
+ tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0)));
+ nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
+ overflow_p);
+ if (*non_constant_p)
+ return NULL_TREE;
+ /* Don't fold an out-of-bound access. */
+ if (!tree_int_cst_le (t, nelts))
+ return NULL_TREE;
+ rhs = cp_fold_convert (ssizetype, rhs);
+ /* Don't fold if rhs can't be divided exactly by TYPE_SIZE_UNIT.
+ constexpr int A[1]; ... (char *)&A[0] + 1 */
+ if (!integer_zerop (fold_build2_loc (loc, TRUNC_MOD_EXPR, sizetype,
+ rhs, TYPE_SIZE_UNIT (type))))
+ return NULL_TREE;
+ /* Make sure to treat the second operand of POINTER_PLUS_EXPR
+ as signed. */
+ rhs = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype, rhs,
+ TYPE_SIZE_UNIT (type));
+ t = size_binop_loc (loc, PLUS_EXPR, rhs, t);
+ t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (lhs, 0),
+ t, NULL_TREE, NULL_TREE);
+ t = cp_build_addr_expr (t, tf_warning_or_error);
+ t = cp_fold_convert (orig_type, t);
+ return cxx_eval_constant_expression (ctx, t, /*lval*/false,
+ non_constant_p, overflow_p);
+ }
+
+ return NULL_TREE;
+}
+
/* Subroutine of cxx_eval_constant_expression.
Like cxx_eval_unary_expression, except for binary expressions. */
@@ -1865,6 +1922,9 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
error ("arithmetic involving a null pointer in %qE", lhs);
return t;
}
+ else if (code == POINTER_PLUS_EXPR)
+ r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p,
+ overflow_p);
if (r == NULL_TREE)
r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -3579,69 +3639,6 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
return NULL_TREE;
}
-/* Subroutine of cxx_eval_constant_expression.
- Attempt to reduce a POINTER_PLUS_EXPR expression T. */
-
-static tree
-cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
- bool lval, bool *non_constant_p,
- bool *overflow_p)
-{
- tree orig_type = TREE_TYPE (t);
- tree op00 = TREE_OPERAND (t, 0);
- tree op01 = TREE_OPERAND (t, 1);
- location_t loc = EXPR_LOCATION (t);
-
- op00 = cxx_eval_constant_expression (ctx, op00, lval,
- non_constant_p, overflow_p);
-
- STRIP_NOPS (op00);
- if (TREE_CODE (op00) != ADDR_EXPR)
- return NULL_TREE;
-
- op01 = cxx_eval_constant_expression (ctx, op01, lval,
- non_constant_p, overflow_p);
- op00 = TREE_OPERAND (op00, 0);
-
- /* &A[i] p+ j => &A[i + j] */
- if (TREE_CODE (op00) == ARRAY_REF
- && TREE_CODE (TREE_OPERAND (op00, 1)) == INTEGER_CST
- && TREE_CODE (op01) == INTEGER_CST
- && TYPE_SIZE_UNIT (TREE_TYPE (op00))
- && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (op00))) == INTEGER_CST)
- {
- tree type = TREE_TYPE (op00);
- t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (op00, 1));
- tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (op00, 0)));
- nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
- overflow_p);
- if (*non_constant_p)
- return NULL_TREE;
- /* Don't fold an out-of-bound access. */
- if (!tree_int_cst_le (t, nelts))
- return NULL_TREE;
- op01 = cp_fold_convert (ssizetype, op01);
- /* Don't fold if op01 can't be divided exactly by TYPE_SIZE_UNIT.
- constexpr int A[1]; ... (char *)&A[0] + 1 */
- if (!integer_zerop (fold_build2_loc (loc, TRUNC_MOD_EXPR, sizetype,
- op01, TYPE_SIZE_UNIT (type))))
- return NULL_TREE;
- /* Make sure to treat the second operand of POINTER_PLUS_EXPR
- as signed. */
- op01 = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype, op01,
- TYPE_SIZE_UNIT (type));
- t = size_binop_loc (loc, PLUS_EXPR, op01, t);
- t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (op00, 0),
- t, NULL_TREE, NULL_TREE);
- t = cp_build_addr_expr (t, tf_warning_or_error);
- t = cp_fold_convert (orig_type, t);
- return cxx_eval_constant_expression (ctx, t, lval, non_constant_p,
- overflow_p);
- }
-
- return NULL_TREE;
-}
-
/* Attempt to reduce the expression T to a constant value.
On failure, issue diagnostic and return error_mark_node. */
/* FIXME unify with c_fully_fold */
@@ -3747,7 +3744,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* Defer in case this is only used for its type. */;
else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
/* Defer, there's no lvalue->rvalue conversion. */;
- else if (is_really_empty_class (TREE_TYPE (t)))
+ else if (COMPLETE_TYPE_P (TREE_TYPE (t))
+ && is_really_empty_class (TREE_TYPE (t)))
{
/* If the class is empty, we aren't actually loading anything. */
r = build_constructor (TREE_TYPE (t), NULL);
@@ -3984,12 +3982,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
break;
case POINTER_PLUS_EXPR:
- r = cxx_eval_pointer_plus_expression (ctx, t, lval, non_constant_p,
- overflow_p);
- if (r)
- break;
- /* fall through */
-
case PLUS_EXPR:
case MINUS_EXPR:
case MULT_EXPR:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5bcb98b9756..f40334092a0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1147,6 +1147,8 @@ enum cp_tree_index
CPTI_NULLPTR,
CPTI_NULLPTR_TYPE,
+ CPTI_ALIGN_TYPE,
+
CPTI_MAX
};
@@ -1182,6 +1184,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#define current_aggr cp_global_trees[CPTI_AGGR_TAG]
#define nullptr_node cp_global_trees[CPTI_NULLPTR]
#define nullptr_type_node cp_global_trees[CPTI_NULLPTR_TYPE]
+/* std::align_val_t */
+#define align_type_node cp_global_trees[CPTI_ALIGN_TYPE]
/* We cache these tree nodes so as to call get_identifier less
frequently. */
@@ -5561,7 +5565,7 @@ extern tree build_user_type_conversion (tree, tree, int,
extern tree build_new_function_call (tree, vec<tree, va_gc> **, bool,
tsubst_flags_t);
extern tree build_operator_new_call (tree, vec<tree, va_gc> **, tree *,
- tree *, tree, tree *,
+ tree *, tree, tree, tree *,
tsubst_flags_t);
extern tree build_new_method_call (tree, tree, vec<tree, va_gc> **,
tree, int, tree *,
@@ -5573,7 +5577,8 @@ extern tree build_new_op (location_t, enum tree_code,
tsubst_flags_t);
extern tree build_op_call (tree, vec<tree, va_gc> **,
tsubst_flags_t);
-extern bool non_placement_deallocation_fn_p (tree);
+extern bool aligned_allocation_fn_p (tree);
+extern bool usual_deallocation_fn_p (tree);
extern tree build_op_delete_call (enum tree_code, tree, tree,
bool, tree, tree,
tsubst_flags_t);
@@ -5966,6 +5971,7 @@ extern tree get_nsdmi (tree, bool);
extern tree build_offset_ref (tree, tree, bool,
tsubst_flags_t);
extern tree throw_bad_array_new_length (void);
+extern bool type_has_new_extended_alignment (tree);
extern tree build_new (vec<tree, va_gc> **, tree, tree,
vec<tree, va_gc> **, int,
tsubst_flags_t);
@@ -6528,6 +6534,7 @@ extern tree build_min_nt_loc (location_t, enum tree_code,
extern tree build_min_non_dep (enum tree_code, tree, ...);
extern tree build_min_non_dep_op_overload (enum tree_code, tree, tree, ...);
extern tree build_min_non_dep_call_vec (tree, tree, vec<tree, va_gc> *);
+extern vec<tree, va_gc>* vec_copy_and_insert (vec<tree, va_gc>*, tree, unsigned);
extern tree build_cplus_new (tree, tree, tsubst_flags_t);
extern tree build_aggr_init_expr (tree, tree);
extern tree get_target_expr (tree);
@@ -6666,7 +6673,7 @@ extern tree build_x_unary_op (location_t,
enum tree_code, cp_expr,
tsubst_flags_t);
extern tree cp_build_addr_expr (tree, tsubst_flags_t);
-extern tree cp_build_unary_op (enum tree_code, tree, int,
+extern tree cp_build_unary_op (enum tree_code, tree, bool,
tsubst_flags_t);
extern tree unary_complex_lvalue (enum tree_code, tree);
extern tree build_x_conditional_expr (location_t, tree, tree, tree,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 43cf3df36ba..2f444656842 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4132,6 +4132,17 @@ cxx_init_decl_processing (void)
/* Now, C++. */
current_lang_name = lang_name_cplusplus;
+ if (aligned_new_threshhold > 1
+ && !pow2p_hwi (aligned_new_threshhold))
+ {
+ error ("-faligned-new=%d is not a power of two", aligned_new_threshhold);
+ aligned_new_threshhold = 1;
+ }
+ if (aligned_new_threshhold == -1)
+ aligned_new_threshhold = (cxx_dialect >= cxx1z) ? 1 : 0;
+ if (aligned_new_threshhold == 1)
+ aligned_new_threshhold = max_align_t_align () / BITS_PER_UNIT;
+
{
tree newattrs, extvisattr;
tree newtype, deltype;
@@ -4199,6 +4210,47 @@ cxx_init_decl_processing (void)
push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
}
+ if (aligned_new_threshhold)
+ {
+ push_namespace (std_identifier);
+ tree align_id = get_identifier ("align_val_t");
+ align_type_node = start_enum (align_id, NULL_TREE, size_type_node,
+ NULL_TREE, /*scoped*/true, NULL);
+ pop_namespace ();
+
+ /* operator new (size_t, align_val_t); */
+ newtype = build_function_type_list (ptr_type_node, size_type_node,
+ align_type_node, NULL_TREE);
+ newtype = cp_build_type_attribute_variant (newtype, newattrs);
+ newtype = build_exception_variant (newtype, new_eh_spec);
+ opnew = push_cp_library_fn (NEW_EXPR, newtype, 0);
+ DECL_IS_MALLOC (opnew) = 1;
+ DECL_IS_OPERATOR_NEW (opnew) = 1;
+ opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
+ DECL_IS_MALLOC (opnew) = 1;
+ DECL_IS_OPERATOR_NEW (opnew) = 1;
+
+ /* operator delete (void *, align_val_t); */
+ deltype = build_function_type_list (void_type_node, ptr_type_node,
+ align_type_node, NULL_TREE);
+ deltype = cp_build_type_attribute_variant (deltype, extvisattr);
+ deltype = build_exception_variant (deltype, empty_except_spec);
+ push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+
+ if (flag_sized_deallocation)
+ {
+ /* operator delete (void *, size_t, align_val_t); */
+ deltype = build_function_type_list (void_type_node, ptr_type_node,
+ size_type_node, align_type_node,
+ NULL_TREE);
+ deltype = cp_build_type_attribute_variant (deltype, extvisattr);
+ deltype = build_exception_variant (deltype, empty_except_spec);
+ push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+ push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+ }
+ }
+
nullptr_type_node = make_node (NULLPTR_TYPE);
TYPE_SIZE (nullptr_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
TYPE_SIZE_UNIT (nullptr_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 55bb987ebbe..4bdac94a8e0 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3775,7 +3775,7 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp)
EQ_EXPR,
cp_build_unary_op (PREINCREMENT_EXPR,
guard,
- /*noconvert=*/1,
+ /*noconvert=*/true,
tf_warning_or_error),
integer_one_node,
tf_warning_or_error);
@@ -3785,7 +3785,7 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp)
EQ_EXPR,
cp_build_unary_op (PREDECREMENT_EXPR,
guard,
- /*noconvert=*/1,
+ /*noconvert=*/true,
tf_warning_or_error),
integer_zero_node,
tf_warning_or_error);
@@ -3861,7 +3861,7 @@ do_static_initialization_or_destruction (tree vars, bool initp)
in other compilation units, or at least those that haven't been
initialized yet. Variables that need dynamic construction in
the current compilation unit are kept accessible. */
- if (flag_sanitize & SANITIZE_ADDRESS)
+ if (initp && (flag_sanitize & SANITIZE_ADDRESS))
finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/false));
node = vars;
@@ -3914,7 +3914,7 @@ do_static_initialization_or_destruction (tree vars, bool initp)
/* Revert what __asan_before_dynamic_init did by calling
__asan_after_dynamic_init. */
- if (flag_sanitize & SANITIZE_ADDRESS)
+ if (initp && (flag_sanitize & SANITIZE_ADDRESS))
finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/true));
/* Finish up the init/destruct if-stmt body. */
@@ -4488,7 +4488,7 @@ maybe_warn_sized_delete (enum tree_code code)
{
tree fn = OVL_CURRENT (ovl);
/* We're only interested in usual deallocation functions. */
- if (!non_placement_deallocation_fn_p (fn))
+ if (!usual_deallocation_fn_p (fn))
continue;
if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
unsized = fn;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 58cd48c0a14..ca7360fa602 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -575,7 +575,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
default:
pp_unsupported_tree (pp, t);
- /* Fall through to error. */
+ /* Fall through. */
case ERROR_MARK:
pp_string (pp, M_("<type error>"));
@@ -959,14 +959,13 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
{
if (flags & TFF_DECL_SPECIFIERS)
{
- if (VAR_P (t)
- && DECL_DECLARED_CONSTEXPR_P (t))
- {
- if (DECL_DECLARED_CONCEPT_P (t))
- pp_cxx_ws_string (pp, "concept");
- else
- pp_cxx_ws_string (pp, "constexpr");
- }
+ if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
+ {
+ if (DECL_LANG_SPECIFIC (t) && DECL_DECLARED_CONCEPT_P (t))
+ pp_cxx_ws_string (pp, "concept");
+ else
+ pp_cxx_ws_string (pp, "constexpr");
+ }
dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME);
pp_maybe_space (pp);
}
@@ -1276,7 +1275,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
default:
pp_unsupported_tree (pp, t);
- /* Fall through to error. */
+ /* Fall through. */
case ERROR_MARK:
pp_string (pp, M_("<declaration error>"));
@@ -2777,7 +2776,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
`report_error_function'. That could cause an infinite loop. */
default:
pp_unsupported_tree (pp, t);
- /* fall through to ERROR_MARK... */
+ /* Fall through. */
case ERROR_MARK:
pp_string (pp, M_("<expression error>"));
break;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 1a5766a42b7..e869542e757 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2569,6 +2569,15 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
}
}
+/* True if alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__. */
+
+bool
+type_has_new_extended_alignment (tree t)
+{
+ return (aligned_new_threshhold
+ && TYPE_ALIGN_UNIT (t) > (unsigned)aligned_new_threshhold);
+}
+
/* Generate code for a new-expression, including calling the "operator
new" function, initializing the object, and, if an exception occurs
during construction, cleaning up. The arguments are as for
@@ -2840,6 +2849,10 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
}
}
+ tree align_arg = NULL_TREE;
+ if (type_has_new_extended_alignment (elt_type))
+ align_arg = build_int_cst (align_type_node, TYPE_ALIGN_UNIT (elt_type));
+
alloc_fn = NULL_TREE;
/* If PLACEMENT is a single simple pointer type not passed by
@@ -2954,12 +2967,28 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
}
return error_mark_node;
}
- alloc_call = build_new_method_call (build_dummy_object (elt_type),
- fns, placement,
- /*conversion_path=*/NULL_TREE,
- LOOKUP_NORMAL,
- &alloc_fn,
- complain);
+ tree dummy = build_dummy_object (elt_type);
+ alloc_call = NULL_TREE;
+ if (align_arg)
+ {
+ vec<tree, va_gc> *align_args
+ = vec_copy_and_insert (*placement, align_arg, 1);
+ alloc_call
+ = build_new_method_call (dummy, fns, &align_args,
+ /*conversion_path=*/NULL_TREE,
+ LOOKUP_NORMAL, &alloc_fn, tf_none);
+ /* If no matching function is found and the allocated object type
+ has new-extended alignment, the alignment argument is removed
+ from the argument list, and overload resolution is performed
+ again. */
+ if (alloc_call == error_mark_node)
+ alloc_call = NULL_TREE;
+ }
+ if (!alloc_call)
+ alloc_call = build_new_method_call (dummy, fns, placement,
+ /*conversion_path=*/NULL_TREE,
+ LOOKUP_NORMAL,
+ &alloc_fn, complain);
}
else
{
@@ -2976,6 +3005,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
alloc_call = build_operator_new_call (fnname, placement,
&size, &cookie_size,
+ align_arg,
outer_nelts_check,
&alloc_fn, complain);
}
@@ -2986,6 +3016,20 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
gcc_assert (alloc_fn != NULL_TREE);
+ if (warn_aligned_new
+ && TYPE_ALIGN (elt_type) > max_align_t_align ()
+ && (warn_aligned_new > 1
+ || CP_DECL_CONTEXT (alloc_fn) == global_namespace)
+ && !aligned_allocation_fn_p (alloc_fn))
+ {
+ warning (OPT_Waligned_new_, "%<new%> of type %qT with extended "
+ "alignment %d", elt_type, TYPE_ALIGN_UNIT (elt_type));
+ inform (input_location, "uses %qD, which does not have an alignment "
+ "parameter", alloc_fn);
+ inform (input_location, "use %<-faligned-new%> to enable C++17 "
+ "over-aligned new support");
+ }
+
/* If we found a simple case of PLACEMENT_EXPR above, then copy it
into a temporary variable. */
if (!processing_template_decl
@@ -4052,13 +4096,14 @@ build_vec_init (tree base, tree maxindex, tree init,
finish_expr_stmt (one_init);
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
- one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, 0, complain);
+ one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, false,
+ complain);
if (one_init == error_mark_node)
errors = true;
else
finish_expr_stmt (one_init);
- one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+ one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
complain);
if (one_init == error_mark_node)
errors = true;
@@ -4111,7 +4156,7 @@ build_vec_init (tree base, tree maxindex, tree init,
finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
build_int_cst (TREE_TYPE (iterator), -1)),
for_stmt, false);
- elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+ elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
complain);
if (elt_init == error_mark_node)
errors = true;
@@ -4228,10 +4273,10 @@ build_vec_init (tree base, tree maxindex, tree init,
finish_expr_stmt (elt_init);
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
- finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
+ finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, false,
complain));
if (base2)
- finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base2, 0,
+ finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base2, false,
complain));
finish_for_stmt (for_stmt);
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index d34743c9c68..bd23260c088 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1740,7 +1740,9 @@ static void
write_real_cst (const tree value)
{
long target_real[4]; /* largest supported float */
- char buffer[9]; /* eight hex digits in a 32-bit number */
+ /* Buffer for eight hex digits in a 32-bit number but big enough
+ even for 64-bit long to avoid warnings. */
+ char buffer[17];
int i, limit, dir;
tree type = TREE_TYPE (value);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 022ab6a2c09..952d8b799ab 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -4707,19 +4707,29 @@ consider_binding_level (tree name, best_match <tree, tree> &bm,
for (tree t = lvl->names; t; t = TREE_CHAIN (t))
{
+ tree d = t;
+
+ /* OVERLOADs or decls from using declaration are wrapped into
+ TREE_LIST. */
+ if (TREE_CODE (d) == TREE_LIST)
+ {
+ d = TREE_VALUE (d);
+ d = OVL_CURRENT (d);
+ }
+
/* Don't use bindings from implicitly declared functions,
as they were likely misspellings themselves. */
- if (TREE_TYPE (t) == error_mark_node)
+ if (TREE_TYPE (d) == error_mark_node)
continue;
/* Skip anticipated decls of builtin functions. */
- if (TREE_CODE (t) == FUNCTION_DECL
- && DECL_BUILT_IN (t)
- && DECL_ANTICIPATED (t))
+ if (TREE_CODE (d) == FUNCTION_DECL
+ && DECL_BUILT_IN (d)
+ && DECL_ANTICIPATED (d))
continue;
- if (DECL_NAME (t))
- bm.consider (DECL_NAME (t));
+ if (DECL_NAME (d))
+ bm.consider (DECL_NAME (d));
}
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ca9f8b9761a..fb88021e237 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2392,7 +2392,7 @@ static tree cp_parser_gnu_attributes_opt
static tree cp_parser_gnu_attribute_list
(cp_parser *);
static tree cp_parser_std_attribute
- (cp_parser *);
+ (cp_parser *, tree);
static tree cp_parser_std_attribute_spec
(cp_parser *);
static tree cp_parser_std_attribute_spec_seq
@@ -21594,7 +21594,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
next_loc = linemap_position_for_loc_and_offset (line_table, loc, 1);
rich_location richloc (line_table, next_loc);
- richloc.add_fixit_insert (next_loc, ";");
+ richloc.add_fixit_insert_before (next_loc, ";");
if (CLASSTYPE_DECLARED_CLASS (type))
error_at_rich_loc (&richloc,
@@ -22037,7 +22037,8 @@ cp_parser_class_head (cp_parser* parser,
class_head_start_location,
get_finish (type_start_token->location));
rich_location richloc (line_table, reported_loc);
- richloc.add_fixit_insert (class_head_start_location, "template <> ");
+ richloc.add_fixit_insert_before (class_head_start_location,
+ "template <> ");
error_at_rich_loc
(&richloc,
"an explicit specialization must be preceded by %<template <>%>");
@@ -24055,9 +24056,9 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
{ balanced-token-seq }. */
static tree
-cp_parser_std_attribute (cp_parser *parser)
+cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
{
- tree attribute, attr_ns = NULL_TREE, attr_id = NULL_TREE, arguments;
+ tree attribute, attr_id = NULL_TREE, arguments;
cp_token *token;
/* First, parse name of the attribute, a.k.a attribute-token. */
@@ -24081,6 +24082,9 @@ cp_parser_std_attribute (cp_parser *parser)
/* We are seeing a scoped attribute token. */
cp_lexer_consume_token (parser->lexer);
+ if (attr_ns)
+ error_at (token->location, "attribute using prefix used together "
+ "with scoped attribute token");
attr_ns = attr_id;
token = cp_lexer_consume_token (parser->lexer);
@@ -24088,6 +24092,8 @@ cp_parser_std_attribute (cp_parser *parser)
attr_id = token->u.value;
else if (token->type == CPP_KEYWORD)
attr_id = ridpointers[(int) token->keyword];
+ else if (token->flags & NAMED_OP)
+ attr_id = get_identifier (cpp_type2name (token->type, token->flags));
else
{
error_at (token->location,
@@ -24098,6 +24104,9 @@ cp_parser_std_attribute (cp_parser *parser)
NULL_TREE);
token = cp_lexer_peek_token (parser->lexer);
}
+ else if (attr_ns)
+ attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
+ NULL_TREE);
else
{
attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
@@ -24191,14 +24200,14 @@ cp_parser_check_std_attribute (tree attributes, tree attribute)
*/
static tree
-cp_parser_std_attribute_list (cp_parser *parser)
+cp_parser_std_attribute_list (cp_parser *parser, tree attr_ns)
{
tree attributes = NULL_TREE, attribute = NULL_TREE;
cp_token *token = NULL;
while (true)
{
- attribute = cp_parser_std_attribute (parser);
+ attribute = cp_parser_std_attribute (parser, attr_ns);
if (attribute == error_mark_node)
break;
if (attribute != NULL_TREE)
@@ -24226,9 +24235,12 @@ cp_parser_std_attribute_list (cp_parser *parser)
/* Parse a standard C++-11 attribute specifier.
attribute-specifier:
- [ [ attribute-list ] ]
+ [ [ attribute-using-prefix [opt] attribute-list ] ]
alignment-specifier
+ attribute-using-prefix:
+ using attribute-namespace :
+
alignment-specifier:
alignas ( type-id ... [opt] )
alignas ( alignment-expression ... [opt] ). */
@@ -24242,10 +24254,39 @@ cp_parser_std_attribute_spec (cp_parser *parser)
if (token->type == CPP_OPEN_SQUARE
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE)
{
+ tree attr_ns = NULL_TREE;
+
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
- attributes = cp_parser_std_attribute_list (parser);
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
+ {
+ token = cp_lexer_peek_nth_token (parser->lexer, 2);
+ if (token->type == CPP_NAME)
+ attr_ns = token->u.value;
+ else if (token->type == CPP_KEYWORD)
+ attr_ns = ridpointers[(int) token->keyword];
+ else if (token->flags & NAMED_OP)
+ attr_ns = get_identifier (cpp_type2name (token->type,
+ token->flags));
+ if (attr_ns
+ && cp_lexer_nth_token_is (parser->lexer, 3, CPP_COLON))
+ {
+ if (cxx_dialect < cxx1z
+ && !in_system_header_at (input_location))
+ pedwarn (input_location, 0,
+ "attribute using prefix only available "
+ "with -std=c++1z or -std=gnu++1z");
+
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else
+ attr_ns = NULL_TREE;
+ }
+
+ attributes = cp_parser_std_attribute_list (parser, attr_ns);
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)
|| !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
@@ -37712,7 +37753,7 @@ cp_parser_cilk_simd_vectorlength (cp_parser *parser, tree clauses,
|| !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
error_at (loc, "vectorlength must be an integer constant");
else if (TREE_CONSTANT (expr)
- && exact_log2 (TREE_INT_CST_LOW (expr)) == -1)
+ && !pow2p_hwi (TREE_INT_CST_LOW (expr)))
error_at (loc, "vectorlength must be a power of 2");
else
{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b0f06649c58..29d8beb33dd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -16257,7 +16257,7 @@ tsubst_copy_and_build (tree t,
case FIX_TRUNC_EXPR:
RETURN (cp_build_unary_op (FIX_TRUNC_EXPR, RECUR (TREE_OPERAND (t, 0)),
- 0, complain));
+ false, complain));
case ADDR_EXPR:
op1 = TREE_OPERAND (t, 0);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 9ab8439077a..e4157325a36 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -588,7 +588,7 @@ simplify_loop_decl_cond (tree *cond_p, tree body)
*cond_p = boolean_true_node;
if_stmt = begin_if_stmt ();
- cond = cp_build_unary_op (TRUTH_NOT_EXPR, cond, 0, tf_warning_or_error);
+ cond = cp_build_unary_op (TRUTH_NOT_EXPR, cond, false, tf_warning_or_error);
finish_if_stmt_cond (cond, if_stmt);
finish_break_stmt ();
finish_then_clause (if_stmt);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 6d254ddbf14..bd2e8f66739 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2920,6 +2920,30 @@ build_min_non_dep_op_overload (enum tree_code op,
return call;
}
+/* Return a new tree vec copied from VEC, with ELT inserted at index IDX. */
+
+vec<tree, va_gc> *
+vec_copy_and_insert (vec<tree, va_gc> *old_vec, tree elt, unsigned idx)
+{
+ unsigned len = vec_safe_length (old_vec);
+ gcc_assert (idx <= len);
+
+ vec<tree, va_gc> *new_vec = NULL;
+ vec_alloc (new_vec, len + 1);
+
+ unsigned i;
+ for (i = 0; i < len; ++i)
+ {
+ if (i == idx)
+ new_vec->quick_push (elt);
+ new_vec->quick_push ((*old_vec)[i]);
+ }
+ if (i == idx)
+ new_vec->quick_push (elt);
+
+ return new_vec;
+}
+
tree
get_type_decl (tree t)
{
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a591d291602..c53a85a16e0 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2208,16 +2208,16 @@ rationalize_conditional_expr (enum tree_code code, tree t,
op1, TREE_CODE (op1),
/*overload=*/NULL,
complain),
- cp_build_unary_op (code, op0, 0, complain),
- cp_build_unary_op (code, op1, 0, complain),
+ cp_build_unary_op (code, op0, false, complain),
+ cp_build_unary_op (code, op1, false, complain),
complain);
}
return
build_conditional_expr (loc, TREE_OPERAND (t, 0),
- cp_build_unary_op (code, TREE_OPERAND (t, 1), 0,
+ cp_build_unary_op (code, TREE_OPERAND (t, 1), false,
complain),
- cp_build_unary_op (code, TREE_OPERAND (t, 2), 0,
+ cp_build_unary_op (code, TREE_OPERAND (t, 2), false,
complain),
complain);
}
@@ -5036,8 +5036,8 @@ cp_build_binary_op (location_t location,
if (first_complex)
{
op0 = save_expr (op0);
- real = cp_build_unary_op (REALPART_EXPR, op0, 1, complain);
- imag = cp_build_unary_op (IMAGPART_EXPR, op0, 1, complain);
+ real = cp_build_unary_op (REALPART_EXPR, op0, true, complain);
+ imag = cp_build_unary_op (IMAGPART_EXPR, op0, true, complain);
switch (code)
{
case MULT_EXPR:
@@ -5056,8 +5056,8 @@ cp_build_binary_op (location_t location,
else
{
op1 = save_expr (op1);
- real = cp_build_unary_op (REALPART_EXPR, op1, 1, complain);
- imag = cp_build_unary_op (IMAGPART_EXPR, op1, 1, complain);
+ real = cp_build_unary_op (REALPART_EXPR, op1, true, complain);
+ imag = cp_build_unary_op (IMAGPART_EXPR, op1, true, complain);
switch (code)
{
case MULT_EXPR:
@@ -5784,11 +5784,10 @@ cp_build_addr_expr_strict (tree arg, tsubst_flags_t complain)
from aggregates to types we don't yet know we want? (Or are those
cases typically errors which should be reported?)
- NOCONVERT nonzero suppresses the default promotions
- (such as from short to int). */
+ NOCONVERT suppresses the default promotions (such as from short to int). */
tree
-cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
+cp_build_unary_op (enum tree_code code, tree xarg, bool noconvert,
tsubst_flags_t complain)
{
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
@@ -5920,9 +5919,9 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
tree real, imag;
arg = cp_stabilize_reference (arg);
- real = cp_build_unary_op (REALPART_EXPR, arg, 1, complain);
- imag = cp_build_unary_op (IMAGPART_EXPR, arg, 1, complain);
- real = cp_build_unary_op (code, real, 1, complain);
+ real = cp_build_unary_op (REALPART_EXPR, arg, true, complain);
+ imag = cp_build_unary_op (IMAGPART_EXPR, arg, true, complain);
+ real = cp_build_unary_op (code, real, true, complain);
if (real == error_mark_node || imag == error_mark_node)
return error_mark_node;
return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
@@ -6030,16 +6029,32 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
complain))
return error_mark_node;
- /* Forbid using -- on `bool'. */
+ /* Forbid using -- or ++ in C++17 on `bool'. */
if (TREE_CODE (declared_type) == BOOLEAN_TYPE)
{
if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
{
if (complain & tf_error)
- error ("invalid use of Boolean expression as operand "
- "to %<operator--%>");
+ error ("use of an operand of type %qT in %<operator--%> "
+ "is forbidden", boolean_type_node);
return error_mark_node;
}
+ else
+ {
+ if (cxx_dialect >= cxx1z)
+ {
+ if (complain & tf_error)
+ error ("use of an operand of type %qT in "
+ "%<operator++%> is forbidden in C++1z",
+ boolean_type_node);
+ return error_mark_node;
+ }
+ /* Otherwise, [depr.incr.bool] says this is deprecated. */
+ else if (!in_system_header_at (input_location))
+ warning (OPT_Wdeprecated, "use of an operand of type %qT "
+ "in %<operator++%> is deprecated",
+ boolean_type_node);
+ }
val = boolean_increment (code, arg);
}
else if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
@@ -6076,7 +6091,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
/* Hook for the c-common bits that build a unary op. */
tree
build_unary_op (location_t /*location*/,
- enum tree_code code, tree xarg, int noconvert)
+ enum tree_code code, tree xarg, bool noconvert)
{
return cp_build_unary_op (code, xarg, noconvert, tf_warning_or_error);
}
@@ -6100,7 +6115,7 @@ unary_complex_lvalue (enum tree_code code, tree arg)
/* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
- tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 1), 0,
+ tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 1), false,
tf_warning_or_error);
return build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
TREE_OPERAND (arg, 0), real_result);
@@ -6134,7 +6149,7 @@ unary_complex_lvalue (enum tree_code code, tree arg)
if (TREE_CODE (arg) == MODIFY_EXPR
|| TREE_CODE (arg) == INIT_EXPR)
{
- tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 0), 0,
+ tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 0), false,
tf_warning_or_error);
arg = build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
arg, real_result);