]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Improve error recovery with constexpr [PR92193]
authorJason Merrill <jason@redhat.com>
Mon, 30 Aug 2021 22:42:05 +0000 (18:42 -0400)
committerJason Merrill <jason@redhat.com>
Tue, 31 Aug 2021 16:17:19 +0000 (12:17 -0400)
The compiler tries to limit error cascades in limit_bad_template_recursion
by avoiding triggering a new instantiation from one that has caused errors.
We were exempting constexpr functions from this because they can be needed
for constant evaluation, but as more and more functions get marked
constexpr, this becomes an over-broad category.  So as suggested on IRC,
this patch only exempts functions that are needed for mandatory constant
evaluation.

As noted in the comment, this flag doesn't particularly need to use a bit in
the FUNCTION_DECL, but there were still some free.

PR c++/92193

gcc/cp/ChangeLog:

* cp-tree.h (FNDECL_MANIFESTLY_CONST_EVALUATED): New.
* constexpr.c (cxx_eval_call_expression): Set it.
* pt.c (neglectable_inst_p): Check it.

gcc/testsuite/ChangeLog:

* g++.dg/diagnostic/static_assert4.C: New test.

gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/diagnostic/static_assert4.C [new file with mode: 0644]

index e78fdf021b23c8e7a9ba4c5f8c6416135ce89e0c..8be88dcfc24fa11b8b91bd20b5db73126bdcc37f 100644 (file)
@@ -2572,6 +2572,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       location_t save_loc = input_location;
       input_location = loc;
       ++function_depth;
+      if (ctx->manifestly_const_eval)
+       FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true;
       instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
       --function_depth;
       input_location = save_loc;
index ce7ca53a113cc2fc25ec053be2c7256d83d01197..f0a7bd24df725fd34240be9608513ffaea408177 100644 (file)
@@ -500,6 +500,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
       OVL_LOOKUP_P (in OVERLOAD)
       LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, NAMESPACE_DECL)
+      FNDECL_MANIFESTLY_CONST_EVALUATED (in FUNCTION_DECL)
    5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
       CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
@@ -4213,6 +4214,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define FNDECL_USED_AUTO(NODE) \
   TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE))
 
+/* True if NODE is needed for a manifestly constant-evaluated expression.
+   This doesn't especially need to be a flag, since currently it's only
+   used for error recovery; if we run out of function flags it could move
+   to an attribute.  */
+#define FNDECL_MANIFESTLY_CONST_EVALUATED(NODE) \
+  TREE_LANG_FLAG_4 (FUNCTION_DECL_CHECK (NODE))
+
 /* True for artificial decls added for OpenMP privatized non-static
    data members.  */
 #define DECL_OMP_PRIVATIZED_MEMBER(NODE) \
index fcf3ac31b258f3d82b731a0105369d2b9b0bd05d..72b22d8c4873fbc28e4be451b5522b7b98abae3d 100644 (file)
@@ -10873,7 +10873,8 @@ neglectable_inst_p (tree d)
 {
   return (d && DECL_P (d)
          && !undeduced_auto_decl (d)
-         && !(TREE_CODE (d) == FUNCTION_DECL ? DECL_DECLARED_CONSTEXPR_P (d)
+         && !(TREE_CODE (d) == FUNCTION_DECL
+              ? FNDECL_MANIFESTLY_CONST_EVALUATED (d)
               : decl_maybe_constant_var_p (d)));
 }
 
diff --git a/gcc/testsuite/g++.dg/diagnostic/static_assert4.C b/gcc/testsuite/g++.dg/diagnostic/static_assert4.C
new file mode 100644 (file)
index 0000000..c539016
--- /dev/null
@@ -0,0 +1,30 @@
+// PR c++/92193
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+  struct has_foo
+  { static constexpr bool value = false; };
+
+template<typename T>
+#ifndef NO_CONSTEXPR
+  constexpr
+#endif
+  bool
+  foo(T t) noexcept(noexcept(t.foo()))
+  { return t.foo(); }
+
+template<typename T>
+  void
+  maybe_foo(T t)
+  {
+    static_assert( has_foo<T>::value, "has foo" ); // { dg-error "has foo" }
+    foo(t);
+  }
+
+struct X { };
+
+int main()
+{
+  X x;
+  maybe_foo(x);
+}