diff mbox

[C++] Reject self-recursive constexpr calls even in templates (PR c++/70449)

Message ID 56FF21C9.4050003@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 2, 2016, 1:35 a.m. UTC
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.
diff mbox

Patch

commit 522aeea737412d552c78b58466280cf9e6c38924
Author: Jason Merrill <jason@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;
+}