diff options
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 42 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-inst1.C | 13 |
3 files changed, 61 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ec827c2..d0ed363 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +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> PR c++/58281 - explicit instantiation of constexpr diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index a099408..944c1cd 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4813,6 +4813,46 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, 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 cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, bool strict = true, tree object = NULL_TREE) @@ -4858,6 +4898,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, r = TARGET_EXPR_INITIAL (r); } + instantiate_constexpr_fns (r); r = cxx_eval_constant_expression (&ctx, r, false, &non_constant_p, &overflow_p); @@ -4959,6 +5000,7 @@ is_sub_constant_expr (tree t) 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, &overflow_p); return !non_constant_p && !overflow_p; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-inst1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-inst1.C new file mode 100644 index 0000000..1016bec --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-inst1.C @@ -0,0 +1,13 @@ +// 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 +} |