diff mbox

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

Message ID 20ed1651-1f55-7a4d-be62-86afacbea64c@redhat.com
State New
Headers show

Commit Message

Jason Merrill May 24, 2016, 3:33 a.m. UTC
On 04/01/2016 09:35 PM, Jason Merrill wrote:
> 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.

This doesn't quite work for the 70344 testcase when optimizing, because 
we call cp_fold_function between when we set DECL_INITIAL to a BLOCK and 
when we lower invisiref parameters, which leads to confusion when we try 
to evaluate a recursive call.  So let's put back the check against 
current_function_decl.

Tested x86_64-pc-linux-gnu, applying to trunk and 6.
diff mbox

Patch

commit a65d5bc7e718824989e02233e6edf990afb15358
Author: Jason Merrill <jason@redhat.com>
Date:   Fri May 20 12:35:30 2016 -0400

    	PR c++/70344 - ICE with recursive constexpr
    
    	* constexpr.c (cxx_eval_call_expression): Check for
    	fun == current_function_decl again.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 7b56260..bb723f4 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1371,11 +1371,17 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
   else
     {
       new_call.fundef = retrieve_constexpr_fundef (fun);
-      if (new_call.fundef == NULL || new_call.fundef->body == NULL)
+      if (new_call.fundef == NULL || new_call.fundef->body == NULL
+	  || fun == current_function_decl)
         {
 	  if (!ctx->quiet)
 	    {
-	      if (DECL_INITIAL (fun) == error_mark_node)
+	      /* We need to check for current_function_decl here in case we're
+		 being called during cp_fold_function, because at that point
+		 DECL_INITIAL is set properly and we have a fundef but we
+		 haven't lowered invisirefs yet (c++/70344).  */
+	      if (DECL_INITIAL (fun) == error_mark_node
+		  || fun == current_function_decl)
 		error_at (loc, "%qD called in a constant expression before its "
 			  "definition is complete", fun);
 	      else if (DECL_INITIAL (fun))
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion2.C
index 978b998..ce2280c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion2.C
@@ -1,5 +1,6 @@ 
 // PR c++/70344
 // { dg-do compile { target c++11 } }
+// { dg-options -O }
 
 struct Z
 {