diff options
author | Jason Merrill <jason@redhat.com> | 2021-10-13 11:47:25 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2021-11-15 18:50:07 -0500 |
commit | 87c2080b056ea2b7f145cba927f36e4f40900205 (patch) | |
tree | f088b9fa589fd828ad401f6555416bc0a343cb9f /gcc/cp/constexpr.c | |
parent | 29e4163a092ce08ba3a88a05ac2fa3f23b1cec28 (diff) | |
download | gcc-87c2080b056ea2b7f145cba927f36e4f40900205.zip gcc-87c2080b056ea2b7f145cba927f36e4f40900205.tar.gz gcc-87c2080b056ea2b7f145cba927f36e4f40900205.tar.bz2 |
c++: Add -fimplicit-constexpr
With each successive C++ standard the restrictions on the use of the
constexpr keyword for functions get weaker and weaker; it recently occurred
to me that it is heading toward the same fate as the C register keyword,
which was once useful for optimization but became obsolete. Similarly, it
seems to me that we should be able to just treat inlines as constexpr
functions and not make people add the extra keyword everywhere.
There were a lot of testcase changes needed; many disabling errors about
non-constexpr functions that are now constexpr, and many disabling implicit
constexpr so that the tests can check the same thing as before, whether
that's mangling or whatever.
gcc/c-family/ChangeLog:
* c.opt: Add -fimplicit-constexpr.
* c-cppbuiltin.c: Define __cpp_implicit_constexpr.
* c-opts.c (c_common_post_options): Disable below C++14.
gcc/cp/ChangeLog:
* cp-tree.h (struct lang_decl_fn): Add implicit_constexpr.
(decl_implicit_constexpr_p): New.
* class.c (type_maybe_constexpr_destructor): Use
TYPE_HAS_TRIVIAL_DESTRUCTOR and maybe_constexpr_fn.
(finalize_literal_type_property): Simplify.
* constexpr.c (is_valid_constexpr_fn): Check for dtor.
(maybe_save_constexpr_fundef): Try to set DECL_DECLARED_CONSTEXPR_P
on inlines.
(cxx_eval_call_expression): Use maybe_constexpr_fn.
(maybe_constexpr_fn): Handle flag_implicit_constexpr.
(var_in_maybe_constexpr_fn): Use maybe_constexpr_fn.
(potential_constant_expression_1): Likewise.
(decl_implicit_constexpr_p): New.
* decl.c (validate_constexpr_redeclaration): Allow change with
-fimplicit-constexpr.
(grok_special_member_properties): Use maybe_constexpr_fn.
* error.c (dump_function_decl): Don't print 'constexpr'
if it's implicit.
* Make-lang.in (check-c++-all): Update.
libstdc++-v3/ChangeLog:
* testsuite/20_util/to_address/1_neg.cc: Adjust error.
* testsuite/26_numerics/random/concept.cc: Adjust asserts.
gcc/testsuite/ChangeLog:
* lib/g++-dg.exp: Handle "impcx".
* lib/target-supports.exp
(check_effective_target_implicit_constexpr): New.
* g++.dg/abi/abi-tag16.C:
* g++.dg/abi/abi-tag18a.C:
* g++.dg/abi/guard4.C:
* g++.dg/abi/lambda-defarg1.C:
* g++.dg/abi/mangle26.C:
* g++.dg/cpp0x/constexpr-diag3.C:
* g++.dg/cpp0x/constexpr-ex1.C:
* g++.dg/cpp0x/constexpr-ice5.C:
* g++.dg/cpp0x/constexpr-incomplete2.C:
* g++.dg/cpp0x/constexpr-memfn1.C:
* g++.dg/cpp0x/constexpr-neg3.C:
* g++.dg/cpp0x/constexpr-specialization.C:
* g++.dg/cpp0x/inh-ctor19.C:
* g++.dg/cpp0x/inh-ctor30.C:
* g++.dg/cpp0x/lambda/lambda-mangle3.C:
* g++.dg/cpp0x/lambda/lambda-mangle5.C:
* g++.dg/cpp1y/auto-fn12.C:
* g++.dg/cpp1y/constexpr-loop5.C:
* g++.dg/cpp1z/constexpr-lambda7.C:
* g++.dg/cpp2a/constexpr-dtor3.C:
* g++.dg/cpp2a/constexpr-new13.C:
* g++.dg/cpp2a/constinit11.C:
* g++.dg/cpp2a/constinit12.C:
* g++.dg/cpp2a/constinit14.C:
* g++.dg/cpp2a/constinit15.C:
* g++.dg/cpp2a/spaceship-constexpr1.C:
* g++.dg/cpp2a/spaceship-eq3.C:
* g++.dg/cpp2a/udlit-class-nttp-neg2.C:
* g++.dg/debug/dwarf2/auto1.C:
* g++.dg/debug/dwarf2/cdtor-1.C:
* g++.dg/debug/dwarf2/lambda1.C:
* g++.dg/debug/dwarf2/pr54508.C:
* g++.dg/debug/dwarf2/pubnames-2.C:
* g++.dg/debug/dwarf2/pubnames-3.C:
* g++.dg/ext/is_literal_type3.C:
* g++.dg/ext/visibility/template7.C:
* g++.dg/gcov/gcov-12.C:
* g++.dg/gcov/gcov-2.C:
* g++.dg/ipa/devirt-35.C:
* g++.dg/ipa/devirt-36.C:
* g++.dg/ipa/devirt-37.C:
* g++.dg/ipa/devirt-44.C:
* g++.dg/ipa/imm-devirt-1.C:
* g++.dg/lookup/builtin5.C:
* g++.dg/lto/inline-crossmodule-1_0.C:
* g++.dg/modules/enum-1_a.C:
* g++.dg/modules/fn-inline-1_c.C:
* g++.dg/modules/pmf-1_b.C:
* g++.dg/modules/used-1_c.C:
* g++.dg/tls/thread_local11.C:
* g++.dg/tls/thread_local11a.C:
* g++.dg/tm/pr46653.C:
* g++.dg/ubsan/pr70035.C:
* g++.old-deja/g++.other/delete6.C:
* g++.dg/modules/pmf-1_a.H:
Adjust for implicit constexpr.
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 85 |
1 files changed, 74 insertions, 11 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c92db5d..69d9d3d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -37,6 +37,8 @@ along with GCC; see the file COPYING3. If not see #include "stor-layout.h" #include "cgraph.h" #include "opts.h" +#include "stringpool.h" +#include "attribs.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -220,6 +222,17 @@ is_valid_constexpr_fn (tree fun, bool complain) inform (DECL_SOURCE_LOCATION (fun), "lambdas are implicitly %<constexpr%> only in C++17 and later"); } + else if (DECL_DESTRUCTOR_P (fun)) + { + if (cxx_dialect < cxx20) + { + ret = false; + if (complain) + error_at (DECL_SOURCE_LOCATION (fun), + "%<constexpr%> destructors only available" + " with %<-std=c++20%> or %<-std=gnu++20%>"); + } + } else if (!DECL_CONSTRUCTOR_P (fun)) { tree rettype = TREE_TYPE (TREE_TYPE (fun)); @@ -865,12 +878,31 @@ void maybe_save_constexpr_fundef (tree fun) { if (processing_template_decl - || !DECL_DECLARED_CONSTEXPR_P (fun) || cp_function_chain->invalid_constexpr || (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun))) return; - bool complain = !DECL_GENERATED_P (fun); + /* With -fimplicit-constexpr, try to make inlines constexpr. We'll + actually set DECL_DECLARED_CONSTEXPR_P below if the checks pass. */ + bool implicit = false; + if (flag_implicit_constexpr) + { + if (DECL_DELETING_DESTRUCTOR_P (fun) + && decl_implicit_constexpr_p (DECL_CLONED_FUNCTION (fun))) + /* Don't inherit implicit constexpr from the non-deleting + destructor. */ + DECL_DECLARED_CONSTEXPR_P (fun) = false; + + if (!DECL_DECLARED_CONSTEXPR_P (fun) + && DECL_DECLARED_INLINE_P (fun) + && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fun))) + implicit = true; + } + + if (!DECL_DECLARED_CONSTEXPR_P (fun) && !implicit) + return; + + bool complain = !DECL_GENERATED_P (fun) && !implicit; if (!is_valid_constexpr_fn (fun, complain)) return; @@ -878,7 +910,7 @@ maybe_save_constexpr_fundef (tree fun) tree massaged = massage_constexpr_body (fun, DECL_SAVED_TREE (fun)); if (massaged == NULL_TREE || massaged == error_mark_node) { - if (!DECL_CONSTRUCTOR_P (fun)) + if (!DECL_CONSTRUCTOR_P (fun) && complain) error ("body of %<constexpr%> function %qD not a return-statement", fun); return; @@ -907,6 +939,21 @@ maybe_save_constexpr_fundef (tree fun) if (!potential && complain) return; + if (implicit) + { + if (potential) + { + DECL_DECLARED_CONSTEXPR_P (fun) = true; + DECL_LANG_SPECIFIC (fun)->u.fn.implicit_constexpr = true; + if (DECL_CONSTRUCTOR_P (fun)) + TYPE_HAS_CONSTEXPR_CTOR (DECL_CONTEXT (fun)) = true; + } + else + /* Don't bother keeping the pre-generic body of unsuitable functions + not explicitly declared constexpr. */ + return; + } + constexpr_fundef entry = {fun, NULL_TREE, NULL_TREE, NULL_TREE}; bool clear_ctx = false; if (DECL_RESULT (fun) && DECL_CONTEXT (DECL_RESULT (fun)) == NULL_TREE) @@ -2404,7 +2451,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, lval, non_constant_p, overflow_p); if (DECL_THUNK_P (fun)) return cxx_eval_thunk_call (ctx, t, fun, lval, non_constant_p, overflow_p); - if (!DECL_DECLARED_CONSTEXPR_P (fun)) + if (!maybe_constexpr_fn (fun)) { if (TREE_CODE (t) == CALL_EXPR && cxx_replaceable_global_alloc_fn (fun) @@ -5229,7 +5276,9 @@ bool maybe_constexpr_fn (tree t) { return (DECL_DECLARED_CONSTEXPR_P (t) - || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t))); + || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t)) + || (flag_implicit_constexpr + && DECL_DECLARED_INLINE_P (STRIP_TEMPLATE (t)))); } /* True if T was declared in a function that might be constexpr: either a @@ -5238,11 +5287,8 @@ maybe_constexpr_fn (tree t) bool var_in_maybe_constexpr_fn (tree t) { - if (cxx_dialect >= cxx17 - && DECL_FUNCTION_SCOPE_P (t) - && LAMBDA_FUNCTION_P (DECL_CONTEXT (t))) - return true; - return var_in_constexpr_fn (t); + return (DECL_FUNCTION_SCOPE_P (t) + && maybe_constexpr_fn (DECL_CONTEXT (t))); } /* We're assigning INIT to TARGET. In do_build_copy_constructor and @@ -8219,7 +8265,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, { if (builtin_valid_in_constant_expr_p (fun)) return true; - if (!DECL_DECLARED_CONSTEXPR_P (fun) + if (!maybe_constexpr_fn (fun) /* Allow any built-in function; if the expansion isn't constant, we'll deal with that then. */ && !fndecl_built_in_p (fun) @@ -9257,6 +9303,23 @@ is_nondependent_static_init_expression (tree t) && !instantiation_dependent_expression_p (t)); } +/* True iff FN is an implicitly constexpr function. */ + +bool +decl_implicit_constexpr_p (tree fn) +{ + if (!(flag_implicit_constexpr + && TREE_CODE (fn) == FUNCTION_DECL + && DECL_DECLARED_CONSTEXPR_P (fn))) + return false; + + if (DECL_CLONED_FUNCTION_P (fn)) + fn = DECL_CLONED_FUNCTION (fn); + + return (DECL_LANG_SPECIFIC (fn) + && DECL_LANG_SPECIFIC (fn)->u.fn.implicit_constexpr); +} + /* Finalize constexpr processing after parsing. */ void |