Commit e079dced by Jason Merrill Committed by Jason Merrill

CWG 1581: When are constexpr member functions defined?

	* constexpr.c (instantiate_cx_fn_r, instantiate_constexpr_fns): New.
	(cxx_eval_outermost_constant_expr): Call instantiate_constexpr_fns.

From-SVN: r261086
parent 7d072b97
2018-05-31 Jason Merrill <jason@redhat.com>
CWG 1581: When are constexpr member functions defined?
* constexpr.c (instantiate_cx_fn_r, instantiate_constexpr_fns): New.
(cxx_eval_outermost_constant_expr): Call instantiate_constexpr_fns.
2018-06-01 Jason Merrill <jason@redhat.com> 2018-06-01 Jason Merrill <jason@redhat.com>
PR c++/58281 - explicit instantiation of constexpr PR c++/58281 - explicit instantiation of constexpr
......
...@@ -4813,6 +4813,46 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -4813,6 +4813,46 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return r; return r;
} }
/* P0859: A function is needed for constant evaluation if it is a constexpr
function that is named by an expression ([basic.def.odr]) that is
potentially constant evaluated.
So we need to instantiate any constexpr functions mentioned by the
expression even if the definition isn't needed for evaluating the
expression. */
static tree
instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void */*data*/)
{
if (TREE_CODE (*tp) == FUNCTION_DECL
&& DECL_DECLARED_CONSTEXPR_P (*tp)
&& !DECL_INITIAL (*tp)
&& DECL_TEMPLOID_INSTANTIATION (*tp))
{
++function_depth;
instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
--function_depth;
}
else if (TREE_CODE (*tp) == CALL_EXPR
|| TREE_CODE (*tp) == AGGR_INIT_EXPR)
{
if (EXPR_HAS_LOCATION (*tp))
input_location = EXPR_LOCATION (*tp);
}
if (!EXPR_P (*tp))
*walk_subtrees = 0;
return NULL_TREE;
}
static void
instantiate_constexpr_fns (tree t)
{
location_t loc = input_location;
cp_walk_tree_without_duplicates (&t, instantiate_cx_fn_r, NULL);
input_location = loc;
}
static tree static tree
cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
bool strict = true, tree object = NULL_TREE) bool strict = true, tree object = NULL_TREE)
...@@ -4858,6 +4898,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, ...@@ -4858,6 +4898,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
r = TARGET_EXPR_INITIAL (r); r = TARGET_EXPR_INITIAL (r);
} }
instantiate_constexpr_fns (r);
r = cxx_eval_constant_expression (&ctx, r, r = cxx_eval_constant_expression (&ctx, r,
false, &non_constant_p, &overflow_p); false, &non_constant_p, &overflow_p);
...@@ -4959,6 +5000,7 @@ is_sub_constant_expr (tree t) ...@@ -4959,6 +5000,7 @@ is_sub_constant_expr (tree t)
constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL, true, true }; constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL, true, true };
instantiate_constexpr_fns (t);
cxx_eval_constant_expression (&ctx, t, false, &non_constant_p, cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
&overflow_p); &overflow_p);
return !non_constant_p && !overflow_p; return !non_constant_p && !overflow_p;
......
// Testcase from P0859
// { dg-do compile { target c++14 } }
template<typename T> constexpr int f() { return T::value; } // { dg-error "int" }
template<bool B, typename T> void g(decltype(B ? f<T>() : 0));
template<bool B, typename T> void g(...);
template<bool B, typename T> void h(decltype(int{B ? f<T>() : 0}));
template<bool B, typename T> void h(...);
void x() {
g<false, int>(0); // OK, B ? f<T>() : 0 is not potentially constant evaluated
h<false, int>(0); // error, instantiates f<int> even though B evaluates to false and
// list-initialization of int from int cannot be narrowing
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment