diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-11-02 00:28:20 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-11-02 00:28:20 +0100 |
commit | f968ef9b8df2bc2287e5e7e87299e5a2a44e8c94 (patch) | |
tree | 6aba8238b5260a14347acaa810dbae9579df6f8d /gcc/cp/constexpr.c | |
parent | 8412b939d1cf375c8e478e39a5ac9d7260e4c23c (diff) | |
download | gcc-f968ef9b8df2bc2287e5e7e87299e5a2a44e8c94.zip gcc-f968ef9b8df2bc2287e5e7e87299e5a2a44e8c94.tar.gz gcc-f968ef9b8df2bc2287e5e7e87299e5a2a44e8c94.tar.bz2 |
PR c++/88335 - Implement P1073R3: Immediate functions
PR c++/88335 - Implement P1073R3: Immediate functions
c-family/
* c-common.h (enum rid): Add RID_CONSTEVAL.
* c-common.c (c_common_reswords): Add consteval.
cp/
* cp-tree.h (struct lang_decl_fn): Add immediate_fn_p bit.
(DECL_IMMEDIATE_FUNCTION_P, SET_DECL_IMMEDIATE_FUNCTION_P): Define.
(enum cp_decl_spec): Add ds_consteval.
(fold_non_dependent_expr): Add another tree argument defaulted to
NULL_TREE.
* name-lookup.h (struct cp_binding_level): Add immediate_fn_ctx_p
member.
* parser.c (cp_keyword_starts_decl_specifier_p): Adjust comments
for C++11 and C++20 specifiers. Handle RID_CONSTEVAL.
(CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Adjust comment.
(CP_PARSER_FLAGS_CONSTEVAL): New.
(cp_parser_skip_balanced_tokens): New forward declaration.
(cp_parser_lambda_declarator_opt): Handle ds_consteval. Set
current_binding_level->immediate_fn_ctx_p before parsing parameter
list if decl-specifier-seq contains consteval specifier.
(cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
(cp_parser_explicit_instantiation): Diagnose explicit instantiation
with consteval specifier.
(cp_parser_init_declarator): For consteval or into flags
CP_PARSER_FLAGS_CONSTEVAL.
(cp_parser_direct_declarator): If CP_PARSER_FLAGS_CONSTEVAL, set
current_binding_level->immediate_fn_ctx_p in the sk_function_parms
scope.
(set_and_check_decl_spec_loc): Add consteval entry, formatting fix.
* call.c (build_addr_func): For direct calls to immediate functions
use build_address rather than decay_conversion.
(build_over_call): Evaluate immediate function invocations.
* error.c (dump_function_decl): Handle DECL_IMMEDIATE_FUNCTION_P.
* semantics.c (expand_or_defer_fn_1): Use tentative linkage and don't
call mark_needed for immediate functions.
* typeck.c (cxx_sizeof_or_alignof_expr): Likewise. Formatting fix.
(cp_build_addr_expr_1): Reject taking address of immediate function
outside of immediate function.
* decl.c (validate_constexpr_redeclaration): Diagnose consteval
vs. non-consteval or vice versa redeclaration. Use
SET_DECL_IMMEDIATE_FUNCTION_P if new_decl is immediate function.
(check_tag_decl): Use %qs with keyword string to simplify translation.
Handle ds_consteval.
(start_decl): Adjust diagnostics for static or thread_local variables
in immediate functions.
(grokfndecl): Call sorry_at on virtual consteval. Use %qs with keyword
to string to simplify translation. Diagnose consteval main. Use
SET_DECL_IMMEDIATE_FUNCTION_P for consteval.
(grokdeclarator): Handle consteval. Use %qs with keyword strings to
simplify translation. Use separate ifs instead of chained else if
for invalid specifiers. For constinit clear constinit_p rather than
constexpr_p.
* constexpr.c (find_immediate_fndecl): New function.
(cxx_eval_outermost_constant_expr): Allow consteval calls returning
void. Diagnose returning address of immediate function from consteval
evaluation.
(fold_non_dependent_expr_template): Add OBJECT argument, pass it
through to cxx_eval_outermost_constant_expr.
(fold_non_dependent_expr): Add OBJECT argument, pass it through to
fold_non_dependent_expr_template.
(fold_non_dependent_init): Adjust fold_non_dependent_expr_template
caller.
* method.c (defaulted_late_check): Adjust diagnostics for consteval.
* lambda.c (maybe_add_lambda_conv_op): Copy over
DECL_DECLARED_CONSTEXPR_P and DECL_IMMEDIATE_FUNCTION_P bits from
callop to both artificial functions.
* init.c (build_value_init): Don't do further processing if
build_special_member_call returned a TREE_CONSTANT. Formatting fix.
testsuite/
* g++.dg/cpp2a/consteval1.C: New test.
* g++.dg/cpp2a/consteval2.C: New test.
* g++.dg/cpp2a/consteval3.C: New test.
* g++.dg/cpp2a/consteval4.C: New test.
* g++.dg/cpp2a/consteval5.C: New test.
* g++.dg/cpp2a/consteval6.C: New test.
* g++.dg/cpp2a/consteval7.C: New test.
* g++.dg/cpp2a/consteval8.C: New test.
* g++.dg/cpp2a/consteval9.C: New test.
* g++.dg/cpp2a/consteval10.C: New test.
* g++.dg/cpp2a/consteval11.C: New test.
* g++.dg/cpp2a/consteval12.C: New test.
* g++.dg/cpp2a/consteval13.C: New test.
* g++.dg/cpp2a/consteval14.C: New test.
* g++.dg/ext/consteval1.C: New test.
From-SVN: r277733
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 70 |
1 files changed, 63 insertions, 7 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 4baaac0..84ed7ac 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5739,6 +5739,16 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/) return NULL_TREE; } +/* Find immediate function decls in *TP if any. */ + +static tree +find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/) +{ + if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp)) + return *tp; + return NULL_TREE; +} + /* ALLOW_NON_CONSTANT is false if T is required to be a constant expression. STRICT has the same sense as for constant_value_1: true if we only allow conforming C++ constant expressions, or false if we want a constant value @@ -5767,13 +5777,38 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, tree type = initialized_type (t); tree r = t; + bool is_consteval = false; if (VOID_TYPE_P (type)) { if (constexpr_dtor) /* Used for destructors of array elements. */ type = TREE_TYPE (object); else - return t; + { + if (cxx_dialect < cxx2a) + return t; + if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR) + return t; + /* Calls to immediate functions returning void need to be + evaluated. */ + tree fndecl = cp_get_callee_fndecl_nofold (t); + if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl)) + return t; + else + is_consteval = true; + } + } + else if (cxx_dialect >= cxx2a + && (TREE_CODE (t) == CALL_EXPR + || TREE_CODE (t) == AGGR_INIT_EXPR + || TREE_CODE (t) == TARGET_EXPR)) + { + tree x = t; + if (TREE_CODE (x) == TARGET_EXPR) + x = TARGET_EXPR_INITIAL (x); + tree fndecl = cp_get_callee_fndecl_nofold (x); + if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl)) + is_consteval = true; } if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) { @@ -5874,6 +5909,25 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, } } + /* Check that immediate invocation does not return an expression referencing + any immediate function decls. They need to be allowed while parsing + immediate functions, but can't leak outside of them. */ + if (is_consteval + && t != r + && (current_function_decl == NULL_TREE + || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))) + if (tree immediate_fndecl + = cp_walk_tree_without_duplicates (&r, find_immediate_fndecl, + NULL)) + { + if (!allow_non_constant && !non_constant_p) + error_at (cp_expr_loc_or_input_loc (t), + "immediate evaluation returns address of immediate " + "function %qD", immediate_fndecl); + r = t; + non_constant_p = true; + } + /* Technically we should check this for all subexpressions, but that runs into problems with our internal representation of pointer subtraction and the 5.19 rules are still in flux. */ @@ -6114,7 +6168,8 @@ clear_cv_and_fold_caches (bool sat /*= true*/) static tree fold_non_dependent_expr_template (tree t, tsubst_flags_t complain, - bool manifestly_const_eval) + bool manifestly_const_eval, + tree object) { gcc_assert (processing_template_decl); @@ -6135,7 +6190,7 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t complain, tree r = cxx_eval_outermost_constant_expr (t, true, true, manifestly_const_eval, - false, NULL_TREE); + false, object); /* cp_tree_equal looks through NOPs, so allow them. */ gcc_checking_assert (r == t || CONVERT_EXPR_P (t) @@ -6171,16 +6226,17 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t complain, tree fold_non_dependent_expr (tree t, tsubst_flags_t complain /* = tf_warning_or_error */, - bool manifestly_const_eval /* = false */) + bool manifestly_const_eval /* = false */, + tree object /* = NULL_TREE */) { if (t == NULL_TREE) return NULL_TREE; if (processing_template_decl) return fold_non_dependent_expr_template (t, complain, - manifestly_const_eval); + manifestly_const_eval, object); - return maybe_constant_value (t, NULL_TREE, manifestly_const_eval); + return maybe_constant_value (t, object, manifestly_const_eval); } @@ -6197,7 +6253,7 @@ fold_non_dependent_init (tree t, if (processing_template_decl) { t = fold_non_dependent_expr_template (t, complain, - manifestly_const_eval); + manifestly_const_eval, NULL_TREE); /* maybe_constant_init does this stripping, so do it here too. */ if (TREE_CODE (t) == TARGET_EXPR) { |