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/decl.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/decl.c')
-rw-r--r-- | gcc/cp/decl.c | 182 |
1 files changed, 146 insertions, 36 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 72acc8f..8f22f23 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1225,7 +1225,13 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl) return true; if (DECL_DECLARED_CONSTEXPR_P (old_decl) == DECL_DECLARED_CONSTEXPR_P (new_decl)) - return true; + { + if (TREE_CODE (old_decl) != FUNCTION_DECL) + return true; + if (DECL_IMMEDIATE_FUNCTION_P (old_decl) + == DECL_IMMEDIATE_FUNCTION_P (new_decl)) + return true; + } if (TREE_CODE (old_decl) == FUNCTION_DECL) { if (fndecl_built_in_p (old_decl)) @@ -1233,6 +1239,8 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl) /* Hide a built-in declaration. */ DECL_DECLARED_CONSTEXPR_P (old_decl) = DECL_DECLARED_CONSTEXPR_P (new_decl); + if (DECL_IMMEDIATE_FUNCTION_P (new_decl)) + SET_DECL_IMMEDIATE_FUNCTION_P (old_decl); return true; } /* 7.1.5 [dcl.constexpr] @@ -1242,9 +1250,14 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl) && DECL_TEMPLATE_SPECIALIZATION (new_decl)) return true; + const char *kind = "constexpr"; + if (DECL_IMMEDIATE_FUNCTION_P (old_decl) + || DECL_IMMEDIATE_FUNCTION_P (new_decl)) + kind = "consteval"; error_at (DECL_SOURCE_LOCATION (new_decl), - "redeclaration %qD differs in %<constexpr%> " - "from previous declaration", new_decl); + "redeclaration %qD differs in %qs " + "from previous declaration", new_decl, + kind); inform (DECL_SOURCE_LOCATION (old_decl), "previous declaration %qD", old_decl); return false; @@ -5024,12 +5037,15 @@ check_tag_decl (cp_decl_specifier_seq *declspecs, else if (saw_typedef) warning_at (declspecs->locations[ds_typedef], 0, "%<typedef%> was ignored in this declaration"); - else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr)) + else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr)) error_at (declspecs->locations[ds_constexpr], - "%<constexpr%> cannot be used for type declarations"); - else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit)) + "%qs cannot be used for type declarations", "constexpr"); + else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit)) error_at (declspecs->locations[ds_constinit], - "%<constinit%> cannot be used for type declarations"); + "%qs cannot be used for type declarations", "constinit"); + else if (decl_spec_seq_has_spec_p (declspecs, ds_consteval)) + error_at (declspecs->locations[ds_consteval], + "%qs cannot be used for type declarations", "consteval"); } if (declspecs->attributes && warn_attributes && declared_type) @@ -5387,11 +5403,14 @@ start_decl (const cp_declarator *declarator, bool ok = false; if (CP_DECL_THREAD_LOCAL_P (decl)) error_at (DECL_SOURCE_LOCATION (decl), - "%qD declared %<thread_local%> in %<constexpr%> function", - decl); + "%qD declared %<thread_local%> in %qs function", 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 %<constexpr%> function", decl); + "%qD declared %<static%> in %qs function", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); else ok = true; if (!ok) @@ -9342,6 +9361,15 @@ grokfndecl (tree ctype, } } + /* FIXME: For now. */ + if (virtualp && (inlinep & 8) != 0) + { + sorry_at (DECL_SOURCE_LOCATION (decl), + "%<virtual%> %<consteval%> method %qD not supported yet", + decl); + inlinep &= ~8; + } + /* If this decl has namespace scope, set that up. */ if (in_namespace) set_decl_namespace (decl, in_namespace, friendp); @@ -9389,7 +9417,10 @@ grokfndecl (tree ctype, "cannot declare %<::main%> to be inline"); if (inlinep & 2) error_at (declspecs->locations[ds_constexpr], - "cannot declare %<::main%> to be %<constexpr%>"); + "cannot declare %<::main%> to be %qs", "constexpr"); + if (inlinep & 8) + error_at (declspecs->locations[ds_consteval], + "cannot declare %<::main%> to be %qs", "consteval"); if (!publicp) error_at (location, "cannot declare %<::main%> to be static"); inlinep = 0; @@ -9428,6 +9459,11 @@ grokfndecl (tree ctype, } if (inlinep & 2) DECL_DECLARED_CONSTEXPR_P (decl) = true; + else if (inlinep & 8) + { + DECL_DECLARED_CONSTEXPR_P (decl) = true; + SET_DECL_IMMEDIATE_FUNCTION_P (decl); + } // If the concept declaration specifier was found, check // that the declaration satisfies the necessary requirements. @@ -10786,6 +10822,7 @@ grokdeclarator (const cp_declarator *declarator, bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef); bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr); bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit); + bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval); bool late_return_type_p = false; bool array_parameter_p = false; tree reqs = NULL_TREE; @@ -11058,17 +11095,31 @@ grokdeclarator (const cp_declarator *declarator, if (name == NULL) name = decl_context == PARM ? "parameter" : "type name"; + if (consteval_p && constexpr_p) + { + error_at (declspecs->locations[ds_consteval], + "both %qs and %qs specified", "constexpr", "consteval"); + return error_mark_node; + } + if (concept_p && typedef_p) { error_at (declspecs->locations[ds_concept], - "%<concept%> cannot appear in a typedef declaration"); + "%qs cannot appear in a typedef declaration", "concept"); return error_mark_node; } if (constexpr_p && typedef_p) { error_at (declspecs->locations[ds_constexpr], - "%<constexpr%> cannot appear in a typedef declaration"); + "%qs cannot appear in a typedef declaration", "constexpr"); + return error_mark_node; + } + + if (consteval_p && typedef_p) + { + error_at (declspecs->locations[ds_consteval], + "%qs cannot appear in a typedef declaration", "consteval"); return error_mark_node; } @@ -11474,21 +11525,31 @@ grokdeclarator (const cp_declarator *declarator, /* Function parameters cannot be concept. */ if (concept_p) - error_at (declspecs->locations[ds_concept], - "a parameter cannot be declared %<concept%>"); + { + error_at (declspecs->locations[ds_concept], + "a parameter cannot be declared %qs", "concept"); + concept_p = 0; + constexpr_p = 0; + } /* Function parameters cannot be constexpr. If we saw one, moan and pretend it wasn't there. */ else if (constexpr_p) { error_at (declspecs->locations[ds_constexpr], - "a parameter cannot be declared %<constexpr%>"); + "a parameter cannot be declared %qs", "constexpr"); constexpr_p = 0; } - else if (constinit_p) + if (constinit_p) { error_at (declspecs->locations[ds_constinit], - "a parameter cannot be declared %<constinit%>"); - constexpr_p = 0; + "a parameter cannot be declared %qs", "constinit"); + constinit_p = 0; + } + if (consteval_p) + { + error_at (declspecs->locations[ds_consteval], + "a parameter cannot be declared %qs", "consteval"); + consteval_p = 0; } } @@ -11511,9 +11572,12 @@ grokdeclarator (const cp_declarator *declarator, if (typedef_p) error_at (declspecs->locations[ds_typedef], "structured binding declaration cannot be %qs", "typedef"); - if (constexpr_p) + if (constexpr_p && !concept_p) error_at (declspecs->locations[ds_constexpr], "structured " "binding declaration cannot be %qs", "constexpr"); + if (consteval_p) + error_at (declspecs->locations[ds_consteval], "structured " + "binding declaration cannot be %qs", "consteval"); if (thread_p && cxx_dialect < cxx2a) pedwarn (declspecs->locations[ds_thread], 0, "structured binding declaration can be %qs only in " @@ -11573,6 +11637,7 @@ grokdeclarator (const cp_declarator *declarator, inlinep = 0; typedef_p = 0; constexpr_p = 0; + consteval_p = 0; concept_p = 0; if (storage_class != sc_static) { @@ -12967,7 +13032,7 @@ grokdeclarator (const cp_declarator *declarator, if (concept_p) { error_at (declspecs->locations[ds_concept], - "a destructor cannot be %<concept%>"); + "a destructor cannot be %qs", "concept"); return error_mark_node; } if (constexpr_p && cxx_dialect < cxx2a) @@ -12977,6 +13042,12 @@ grokdeclarator (const cp_declarator *declarator, " with %<-std=c++2a%> or %<-std=gnu++2a%>"); return error_mark_node; } + if (consteval_p) + { + error_at (declspecs->locations[ds_consteval], + "a destructor cannot be %qs", "consteval"); + return error_mark_node; + } } else if (sfk == sfk_constructor && friendp && !ctype) { @@ -12998,6 +13069,14 @@ grokdeclarator (const cp_declarator *declarator, "a concept cannot be a member function"); concept_p = false; } + else if (consteval_p + && identifier_p (unqualified_id) + && IDENTIFIER_NEWDEL_OP_P (unqualified_id)) + { + error_at (declspecs->locations[ds_consteval], + "%qD cannot be %qs", unqualified_id, "consteval"); + consteval_p = false; + } if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) { @@ -13028,7 +13107,8 @@ grokdeclarator (const cp_declarator *declarator, reqs, virtualp, flags, memfn_quals, rqual, raises, friendp ? -1 : 0, friendp, publicp, - inlinep | (2 * constexpr_p) | (4 * concept_p), + inlinep | (2 * constexpr_p) | (4 * concept_p) + | (8 * consteval_p), initialized == SD_DELETED, sfk, funcdef_flag, late_return_type_p, template_count, in_namespace, @@ -13130,8 +13210,8 @@ grokdeclarator (const cp_declarator *declarator, set_linkage_for_static_data_member (decl); if (concept_p) error_at (declspecs->locations[ds_concept], - "static data member %qE declared %<concept%>", - unqualified_id); + "static data member %qE declared %qs", + unqualified_id, "concept"); else if (constexpr_p && !initialized) { error_at (DECL_SOURCE_LOCATION (decl), @@ -13139,6 +13219,10 @@ grokdeclarator (const cp_declarator *declarator, "have an initializer", decl); constexpr_p = false; } + if (consteval_p) + error_at (declspecs->locations[ds_consteval], + "static data member %qE declared %qs", + unqualified_id, "consteval"); if (inlinep) mark_inline_variable (decl, declspecs->locations[ds_inline]); @@ -13163,23 +13247,34 @@ grokdeclarator (const cp_declarator *declarator, else { if (concept_p) - error_at (declspecs->locations[ds_concept], - "non-static data member %qE declared %<concept%>", - unqualified_id); - else if (constexpr_p) + { + error_at (declspecs->locations[ds_concept], + "non-static data member %qE declared %qs", + unqualified_id, "concept"); + concept_p = false; + constexpr_p = false; + } + else if (constexpr_p) { error_at (declspecs->locations[ds_constexpr], - "non-static data member %qE declared " - "%<constexpr%>", unqualified_id); + "non-static data member %qE declared %qs", + unqualified_id, "constexpr"); constexpr_p = false; } - else if (constinit_p) + if (constinit_p) { error_at (declspecs->locations[ds_constinit], - "non-static data member %qE declared " - "%<constinit%>", unqualified_id); + "non-static data member %qE declared %qs", + unqualified_id, "constinit"); constinit_p = false; } + if (consteval_p) + { + error_at (declspecs->locations[ds_consteval], + "non-static data member %qE declared %qs", + unqualified_id, "consteval"); + consteval_p = false; + } decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type); DECL_NONADDRESSABLE_P (decl) = bitfield; if (bitfield && !unqualified_id) @@ -13285,6 +13380,14 @@ grokdeclarator (const cp_declarator *declarator, sfk = sfk_none; } } + if (consteval_p + && identifier_p (unqualified_id) + && IDENTIFIER_NEWDEL_OP_P (unqualified_id)) + { + error_at (declspecs->locations[ds_consteval], + "%qD cannot be %qs", unqualified_id, "consteval"); + consteval_p = false; + } /* Record whether the function is public. */ publicp = (ctype != NULL_TREE @@ -13295,7 +13398,8 @@ grokdeclarator (const cp_declarator *declarator, reqs, virtualp, flags, memfn_quals, rqual, raises, 1, friendp, publicp, - inlinep | (2 * constexpr_p) | (4 * concept_p), + inlinep | (2 * constexpr_p) | (4 * concept_p) + | (8 * consteval_p), initialized == SD_DELETED, sfk, funcdef_flag, @@ -13388,6 +13492,12 @@ grokdeclarator (const cp_declarator *declarator, "is not a definition", decl); constexpr_p = false; } + if (consteval_p) + { + error_at (DECL_SOURCE_LOCATION (decl), + "a variable cannot be declared %<consteval%>"); + consteval_p = false; + } if (inlinep) mark_inline_variable (decl, declspecs->locations[ds_inline]); @@ -16696,7 +16806,7 @@ finish_function (bool inline_p) invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl); /* Perform delayed folding before NRV transformation. */ - if (!processing_template_decl) + if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl)) cp_fold_function (fndecl); /* Set up the named return value optimization, if we can. Candidate @@ -16813,7 +16923,7 @@ finish_function (bool inline_p) do_warn_unused_parameter (fndecl); /* Genericize before inlining. */ - if (!processing_template_decl) + if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl)) cp_genericize (fndecl); /* We're leaving the context of this function, so zap cfun. It's still in |