CWG 1581: When are constexpr member functions defined?
authorJason Merrill <jason@redhat.com>
Fri, 1 Jun 2018 20:49:43 +0000 (16:49 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 1 Jun 2018 20:49:43 +0000 (16:49 -0400)
* constexpr.c (instantiate_cx_fn_r, instantiate_constexpr_fns): New.
(cxx_eval_outermost_constant_expr): Call instantiate_constexpr_fns.

From-SVN: r261086

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/cpp2a/constexpr-inst1.C [new file with mode: 0644]

index ec827c251089ca7959e32695b43f6adf8b33d9b1..d0ed3634a71edf520140290b2f031d8690abc7d8 100644 (file)
@@ -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
index a099408dd2823bded9e8864cffa16131a2e6838f..944c1cdf11ecf934b40ed7667bac7afaca388f86 100644 (file)
@@ -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 (file)
index 0000000..1016bec
--- /dev/null
@@ -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
+}