aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constexpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r--gcc/cp/constexpr.c85
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