This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Reject self-recursive constexpr calls even in templates (PR c++/70449)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 1 Apr 2016 21:19:41 +0200
- Subject: [C++ PATCH] Reject self-recursive constexpr calls even in templates (PR c++/70449)
- Authentication-results: sourceware.org; auth=none
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
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.
The patch attempts to reject that.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2016-04-01 Jakub Jelinek <jakub@redhat.com>
PR c++/70449
* constexpr.c (cxx_eval_call_expression): Before calling
instantiate_decl check if not trying to instantiate current
function template and handle that the same as if
fun == current_function_decl.
* g++.dg/cpp1y/pr70449.C: New test.
--- gcc/cp/constexpr.c.jj 2016-03-29 19:31:21.000000000 +0200
+++ gcc/cp/constexpr.c 2016-04-01 16:26:53.591088640 +0200
@@ -1293,6 +1293,27 @@ cxx_eval_call_expression (const constexp
if (!DECL_INITIAL (fun)
&& DECL_TEMPLOID_INSTANTIATION (fun))
{
+ tree d = fun;
+ if (DECL_CLONED_FUNCTION_P (d))
+ d = DECL_CLONED_FUNCTION (d);
+ d = template_for_substitution (d);
+ if (DECL_TEMPLATE_RESULT (d) == current_function_decl)
+ {
+ /* A call to the current function template, i.e.
+ template <typename T>
+ constexpr int f (int i) {
+ constexpr int j = f<T>(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;
+ }
+
++function_depth;
instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
--function_depth;
--- gcc/testsuite/g++.dg/cpp1y/pr70449.C.jj 2016-04-01 16:42:55.055190752 +0200
+++ gcc/testsuite/g++.dg/cpp1y/pr70449.C 2016-04-01 16:43:43.207545314 +0200
@@ -0,0 +1,26 @@
+// 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;
+}
+
+template <int N>
+constexpr int f2 ()
+{
+ enum E { a = f2<0> () };
+ 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;
+}
+
+constexpr int c = f1<0> ();
+constexpr int d = f3 ();
Jakub