From: Jakub Jelinek Date: Tue, 25 Oct 2016 08:47:15 +0000 (+0200) Subject: internal-fn.def (LAUNDER): New internal function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e16f1cc79dc131b0762cec4c18cfcd795fb6fe75;p=gcc.git internal-fn.def (LAUNDER): New internal function. * internal-fn.def (LAUNDER): New internal function. * internal-fn.c (expand_LAUNDER): New function. c-family/ * c-common.h (enum rid): Add RID_BUILTIN_LAUNDER. * c-common.c (c_common_reswords): Add __builtin_launder. cp/ * cp-tree.h (finish_builtin_launder): Declare. * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_LAUNDER. * semantics.c (finish_builtin_launder): New function. * pt.c (tsubst_copy_and_build): Handle instantiation of IFN_LAUNDER. * constexpr.c (cxx_eval_internal_function): Handle IFN_LAUNDER. (potential_constant_expression_1): Likewise. testsuite/ * g++.dg/cpp1z/launder1.C: New test. * g++.dg/cpp1z/launder2.C: New test. From-SVN: r241506 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cb290f18818..c8331867dc0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,10 @@ +2016-10-25 Jakub Jelinek + + * internal-fn.def (LAUNDER): New internal function. + * internal-fn.c (expand_LAUNDER): New function. + 2016-10-25 Georg-Johann Lay + Pitchumani Sivanupandi New avr target pass to work around performance loss by PR fix. @@ -18,7 +24,7 @@ (avr_optimize_casesi): New functions. 2016-10-25 Georg-Johann Lay - Pitchumani Sivanupandi + Pitchumani Sivanupandi PR target/71676 PR target/71678 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 6a6dba28593..15d7488ba04 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2016-10-25 Jakub Jelinek + + * c-common.h (enum rid): Add RID_BUILTIN_LAUNDER. + * c-common.c (c_common_reswords): Add __builtin_launder. + 2016-10-24 Bernd Edlinger * c-common.c (c_common_truthvalue_conversion): Warn for diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index c0dafc08652..307862b9c7c 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -375,6 +375,7 @@ const struct c_common_resword c_common_reswords[] = RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY }, { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY }, + { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY }, { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, { "__builtin_offsetof", RID_OFFSETOF, 0 }, { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index bfdbda0898d..547bab2ac4e 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -146,8 +146,8 @@ enum rid RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, /* C++ extensions */ - RID_ADDRESSOF, - RID_BASES, RID_DIRECT_BASES, + RID_ADDRESSOF, RID_BASES, + RID_BUILTIN_LAUNDER, RID_DIRECT_BASES, RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 744eb5288a2..21c6408b1a0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2016-10-25 Jakub Jelinek + + * cp-tree.h (finish_builtin_launder): Declare. + * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_LAUNDER. + * semantics.c (finish_builtin_launder): New function. + * pt.c (tsubst_copy_and_build): Handle instantiation of IFN_LAUNDER. + * constexpr.c (cxx_eval_internal_function): Handle IFN_LAUNDER. + (potential_constant_expression_1): Likewise. + 2016-10-24 Jakub Jelinek * cp-objcp-common.c (cp_decl_dwarf_attribute): Handle DW_AT_reference diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 3c4fcfaeef9..8f7b7f34b64 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1330,6 +1330,10 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, opcode = MULT_EXPR; break; + case IFN_LAUNDER: + return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), + false, non_constant_p, overflow_p); + default: if (!ctx->quiet) error_at (EXPR_LOC_OR_LOC (t, input_location), @@ -4920,6 +4924,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case IFN_ADD_OVERFLOW: case IFN_SUB_OVERFLOW: case IFN_MUL_OVERFLOW: + case IFN_LAUNDER: bail = false; default: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f4a8985b351..c58996925c3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6494,6 +6494,8 @@ extern bool generic_lambda_fn_p (tree); extern void maybe_add_lambda_conv_op (tree); extern bool is_lambda_ignored_entity (tree); extern bool lambda_static_thunk_p (tree); +extern tree finish_builtin_launder (location_t, tree, + tsubst_flags_t); /* in tree.c */ extern int cp_tree_operand_length (const_tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 643c1e7bfe9..f962dfb0759 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6604,6 +6604,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_ADDRESSOF: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_LAUNDER: { vec *vec; unsigned int i; @@ -6628,6 +6629,18 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, "%<__builtin_addressof%>"); return error_mark_node; + case RID_BUILTIN_LAUNDER: + if (vec->length () == 1) + postfix_expression = finish_builtin_launder (loc, (*vec)[0], + tf_warning_or_error); + else + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_launder%>"); + postfix_expression = error_mark_node; + } + break; + case RID_BUILTIN_SHUFFLE: if (vec->length () == 2) return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index aa126a0b94c..c916e58482f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16599,19 +16599,19 @@ tsubst_copy_and_build (tree t, tree ret; function = CALL_EXPR_FN (t); - if (function == NULL_TREE) - { - /* If you hit this assert, it means that you're trying to tsubst - an internal function with arguments. This isn't yet supported, - so you need to build another internal call with the tsubsted - arguments after the arguments have been tsubsted down below. */ - gcc_assert (call_expr_nargs (t) == 0); - RETURN (t); - } + /* Internal function with no arguments. */ + if (function == NULL_TREE && call_expr_nargs (t) == 0) + RETURN (t); + /* When we parsed the expression, we determined whether or not Koenig lookup should be performed. */ koenig_p = KOENIG_LOOKUP_P (t); - if (TREE_CODE (function) == SCOPE_REF) + if (function == NULL_TREE) + { + koenig_p = false; + qualified_p = false; + } + else if (TREE_CODE (function) == SCOPE_REF) { qualified_p = true; function = tsubst_qualified_id (function, args, complain, in_decl, @@ -16709,7 +16709,8 @@ tsubst_copy_and_build (tree t, && !any_type_dependent_arguments_p (call_args)) function = perform_koenig_lookup (function, call_args, tf_none); - if (identifier_p (function) + if (function != NULL_TREE + && identifier_p (function) && !any_type_dependent_arguments_p (call_args)) { if (koenig_p && (complain & tf_warning_or_error)) @@ -16721,7 +16722,10 @@ tsubst_copy_and_build (tree t, (function, args, complain, in_decl, true, integral_constant_expression_p)); if (unq == error_mark_node) - RETURN (error_mark_node); + { + release_tree_vector (call_args); + RETURN (error_mark_node); + } if (unq != function) { @@ -16774,14 +16778,40 @@ tsubst_copy_and_build (tree t, } /* Remember that there was a reference to this entity. */ - if (DECL_P (function) + if (function != NULL_TREE + && DECL_P (function) && !mark_used (function, complain) && !(complain & tf_error)) - RETURN (error_mark_node); + { + release_tree_vector (call_args); + RETURN (error_mark_node); + } /* Put back tf_decltype for the actual call. */ complain |= decltype_flag; - if (TREE_CODE (function) == OFFSET_REF) + if (function == NULL_TREE) + switch (CALL_EXPR_IFN (t)) + { + case IFN_LAUNDER: + gcc_assert (nargs == 1); + if (vec_safe_length (call_args) != 1) + { + error_at (EXPR_LOC_OR_LOC (t, input_location), + "wrong number of arguments to " + "%<__builtin_launder%>"); + ret = error_mark_node; + } + else + ret = finish_builtin_launder (EXPR_LOC_OR_LOC (t, + input_location), + (*call_args)[0], complain); + break; + + default: + /* Unsupported internal function with arguments. */ + gcc_unreachable (); + } + else if (TREE_CODE (function) == OFFSET_REF) ret = build_offset_ref_call_from_tree (function, &call_args, complain); else if (TREE_CODE (function) == COMPONENT_REF) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 968f88b3c04..1a7c478d4ec 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9449,4 +9449,26 @@ finish_binary_fold_expr (tree expr1, tree expr2, int op) return error_mark_node; } +/* Finish __builtin_launder (arg). */ + +tree +finish_builtin_launder (location_t loc, tree arg, tsubst_flags_t complain) +{ + tree orig_arg = arg; + if (!type_dependent_expression_p (arg)) + arg = decay_conversion (arg, complain); + if (error_operand_p (arg)) + return error_mark_node; + if (!type_dependent_expression_p (arg) + && TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) + { + error_at (loc, "non-pointer argument to %<__builtin_launder%>"); + return error_mark_node; + } + if (processing_template_decl) + arg = orig_arg; + return build_call_expr_internal_loc (loc, IFN_LAUNDER, + TREE_TYPE (arg), 1, arg); +} + #include "gt-cp-semantics.h" diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 0b32d5f635b..44776976d2a 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -2207,6 +2207,19 @@ expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call) expand_ifn_atomic_compare_exchange (call); } +/* Expand LAUNDER to assignment, lhs = arg0. */ + +static void +expand_LAUNDER (internal_fn, gcall *call) +{ + tree lhs = gimple_call_lhs (call); + + if (!lhs) + return; + + expand_assignment (lhs, gimple_call_arg (call, 0), false); +} + /* Expand a call to FN using the operands in STMT. FN has a single output operand and NARGS input operands. */ diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index d4fbdb28622..28863dfe4b3 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -198,6 +198,9 @@ DEF_INTERNAL_FN (ATOMIC_COMPARE_EXCHANGE, ECF_LEAF | ECF_NOTHROW, NULL) /* To implement [[fallthrough]]. */ DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL) +/* To implement __builtin_launder. */ +DEF_INTERNAL_FN (LAUNDER, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL) + #undef DEF_INTERNAL_INT_FN #undef DEF_INTERNAL_FLT_FN #undef DEF_INTERNAL_OPTAB_FN diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4fa3b4f9b64..1dc07326565 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,11 +1,17 @@ +2016-10-25 Jakub Jelinek + + * g++.dg/cpp1z/launder1.C: New test. + * g++.dg/cpp1z/launder2.C: New test. + 2016-10-25 Georg-Johann Lay + Pitchumani Sivanupandi PR target/71676 PR target/71678 * gcc.target/avr/pr71676-2.c: New test. 2016-10-25 Georg-Johann Lay - Pitchumani Sivanupandi + Pitchumani Sivanupandi PR target/71676 PR target/71678 diff --git a/gcc/testsuite/g++.dg/cpp1z/launder1.C b/gcc/testsuite/g++.dg/cpp1z/launder1.C new file mode 100644 index 00000000000..8f3b022f011 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/launder1.C @@ -0,0 +1,51 @@ +// { dg-do run { target c++11 } } +// { dg-additional-options "-O2" } + +void * +operator new (decltype (sizeof (0)), void *p) +{ + return p; +} + +namespace std +{ + template + T * + launder (T *p) + { + return __builtin_launder (p); + } +} + +struct A +{ + virtual int f (); +}; + +struct B : A +{ + virtual int f () + { + new (this) A; + return 1; + } +}; + +int +A::f () +{ + new (this) B; + return 2; +} + +static_assert (sizeof (B) == sizeof (A), ""); + +int +main () +{ + A a; + int n = a.f (); + int m = std::launder (&a)->f (); + if (n != 2 || m != 1) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/launder2.C b/gcc/testsuite/g++.dg/cpp1z/launder2.C new file mode 100644 index 00000000000..9cd1779704b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/launder2.C @@ -0,0 +1,42 @@ +// { dg-do compile { target c++11 } } + +int a; +int *b = __builtin_launder (); // { dg-error "wrong number of arguments to" } +int *c = __builtin_launder (&a, 2); // { dg-error "wrong number of arguments to" } +int *d = __builtin_launder (&a); +int e = __builtin_launder (a); // { dg-error "non-pointer argument to" } +int &f = a; +int g = __builtin_launder (f); // { dg-error "non-pointer argument to" } + +template T f1 (T x) { return __builtin_launder (x); } // { dg-error "non-pointer argument to" } +template T f2 (T x) { return __builtin_launder (x); } + +int h = f1 (a); +int *i = f2 (&a); +struct S { long s; int foo (); } *j; +S *k = f2 (j); +int l = __builtin_launder (j)->foo (); + +template T *f3 (T *x) { return __builtin_launder (x); } + +long *m; +long *n = f3 (m); +int *o = f3 (&a); + +template T *f4 (U... x) { return __builtin_launder (x...); } +template T *f5 (U... x) { return __builtin_launder (x...); } // { dg-error "wrong number of arguments to" } +template T *f6 (U... x) { return __builtin_launder (x...); } // { dg-error "wrong number of arguments to" } +template T f7 (T x, U... y) { return __builtin_launder (x, y...); } // { dg-error "wrong number of arguments to" } + +long *p = f4 (m); +long *q = f5 (); +long *r = f6 (m, 1); +S s; +int t = __builtin_launder (&s)->foo (); + +constexpr const int *f8 (const int *x) { return __builtin_launder (x); } +template constexpr T f9 (T x) { return __builtin_launder (x); } +constexpr int u = 6; +constexpr const int *v = f8 (&u); +constexpr const int *w = f9 (&u); +static_assert (*f8 (&u) == 6 && *f9 (&u) == 6, "");