aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/constexpr.c42
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-inst1.C13
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
+}