On 04/01/2016 09:34 PM, Jason Merrill wrote:
On 04/01/2016 03:19 PM, Jakub Jelinek wrote:
As the testcase shows, when not in a template, cxx_eval_call_expression
already complains about self-recursive calls in constexpr contexts,
but if we are in a function template, we ICE on the testcase,
because we try to instantiate the function template we are in the
middle of
parsing, e.g. function_end_locus is UNKNOWN_LOCATION, and only the
statements that have been already parsed are in there.
That's odd, we should have failed to instantiate the template.
Investigating further, it seems that we can check for DECL_INITIAL ==
error_mark_node to tell that a function is still being defined. So this
patch does that, and also replaces my earlier fix for 70344.
Tested x86_64-pc-linux-gnu, applying to trunk.
...with the patch.
commit 522aeea737412d552c78b58466280cf9e6c38924
Author: Jason Merrill <ja...@redhat.com>
Date: Fri Apr 1 20:30:09 2016 -0400
PR c++/70449
PR c++/70344
* pt.c (instantiate_decl): A function isn't fully defined if
DECL_INITIAL is error_mark_node.
* constexpr.c (cxx_eval_call_expression): Likewise.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index ea605dc..979f01f 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1239,21 +1239,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
return t;
}
- if (fun == current_function_decl)
- {
- /* A call to the current function, i.e.
- constexpr int f (int i) {
- constexpr int j = f(i-1);
- return j;
- }
- This would be OK without the constexpr on the declaration of j. */
- if (!ctx->quiet)
- error_at (loc, "%qD called in a constant expression before its "
- "definition is complete", fun);
- *non_constant_p = true;
- return t;
- }
-
constexpr_ctx new_ctx = *ctx;
if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
&& TREE_CODE (t) == AGGR_INIT_EXPR)
@@ -1308,7 +1293,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{
if (!ctx->quiet)
{
- if (DECL_INITIAL (fun))
+ if (DECL_INITIAL (fun) == error_mark_node)
+ error_at (loc, "%qD called in a constant expression before its "
+ "definition is complete", fun);
+ else if (DECL_INITIAL (fun))
{
/* The definition of fun was somehow unsuitable. */
error_at (loc, "%qD called in a constant expression", fun);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a6398c0..2d93a5c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -21741,7 +21741,8 @@ instantiate_decl (tree d, int defer_ok,
if (TREE_CODE (d) == FUNCTION_DECL)
{
deleted_p = DECL_DELETED_FN (code_pattern);
- pattern_defined = (DECL_SAVED_TREE (code_pattern) != NULL_TREE
+ pattern_defined = ((DECL_SAVED_TREE (code_pattern) != NULL_TREE
+ && DECL_INITIAL (code_pattern) != error_mark_node)
|| DECL_DEFAULTED_OUTSIDE_CLASS_P (code_pattern)
|| deleted_p);
}
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion1.C
new file mode 100644
index 0000000..79e0b5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-recursion1.C
@@ -0,0 +1,16 @@
+// PR c++/70449
+// { dg-do compile { target c++14 } }
+// { dg-options "-Wall" }
+
+template <int N>
+constexpr int f1 ()
+{
+ enum E { a = f1<0> () }; // { dg-error "called in a constant expression before its definition is complete|is not an integer constant" }
+ return 0;
+}
+
+constexpr int f3 ()
+{
+ enum E { a = f3 () }; // { dg-error "called in a constant expression before its definition is complete|is not an integer constant" }
+ return 0;
+}