C++ PATCH to fix wrong-code with constexpr call table cache (PR c++/83116)

Marek Polacek polacek@redhat.com
Mon Dec 18 15:09:00 GMT 2017


Here the problem was that cxx_eval_call_expression can cache the result of a
constexpr call in constexpr_call_table, but we have to be careful, after
store_init_value the result might be invalid.  So I believe we also have to
clear the constexpr call table.  I've lumped it together with clearing
cv_cache.

Bootstrapped/regtested on x86_64-linux, ok for trunk and 7?

2017-12-18  Marek Polacek  <polacek@redhat.com>

	PR c++/83116
	* constexpr.c (clear_cv_cache): Renamed to ...
	(clear_constexpr_cache): ... this.  Also clear constexpr_call_table.
	(clear_cv_and_fold_caches): Renamed to ...
	(clear_constexpr_and_fold_caches): ... this.
	* cp-tree.h (clear_constexpr_and_fold_caches): Update declaration.
	* decl.c (finish_enum_value_list): Call clear_constexpr_and_fold_caches
	instead of clear_cv_and_fold_caches.
	* typeck2.c (store_init_value): Likewise.

	* g++.dg/cpp1y/constexpr-83116.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 0455be1d6da..e0299e731f0 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -4992,21 +4992,23 @@ maybe_constant_value (tree t, tree decl)
   return r;
 }
 
-/* Dispose of the whole CV_CACHE.  */
+/* Dispose of the whole CV_CACHE and CONSTEXPR_CALL_TABLE.  */
 
 static void
-clear_cv_cache (void)
+clear_constexpr_cache (void)
 {
   if (cv_cache != NULL)
     cv_cache->empty ();
+  if (constexpr_call_table != NULL)
+    constexpr_call_table->empty ();
 }
 
-/* Dispose of the whole CV_CACHE and FOLD_CACHE.  */
+/* Clear the constexpr caches and FOLD_CACHE.  */
 
 void
-clear_cv_and_fold_caches (void)
+clear_constexpr_and_fold_caches (void)
 {
-  clear_cv_cache ();
+  clear_constexpr_cache ();
   clear_fold_cache ();
 }
 
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index f5f974da728..6e553c4f62d 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -7409,7 +7409,7 @@ extern bool var_in_maybe_constexpr_fn           (tree);
 extern void explain_invalid_constexpr_fn        (tree);
 extern vec<tree> cx_error_context               (void);
 extern tree fold_sizeof_expr			(tree);
-extern void clear_cv_and_fold_caches		(void);
+extern void clear_constexpr_and_fold_caches	(void);
 
 /* In cp-ubsan.c */
 extern void cp_ubsan_maybe_instrument_member_call (tree);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index ca9e0c7b205..bed2280b9e4 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -14341,7 +14341,7 @@ finish_enum_value_list (tree enumtype)
 
   /* Each enumerator now has the type of its enumeration.  Clear the cache
      so that this change in types doesn't confuse us later on.  */
-  clear_cv_and_fold_caches ();
+  clear_constexpr_and_fold_caches ();
 }
 
 /* Finishes the enum type. This is called only the first time an
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index e5bb249b2be..787e59b70d8 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -845,7 +845,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
   value = replace_placeholders (value, decl);
 
   /* DECL may change value; purge caches.  */
-  clear_cv_and_fold_caches ();
+  clear_constexpr_and_fold_caches ();
 
   /* If the initializer is not a constant, fill in DECL_INITIAL with
      the bits that are constant, and then return an expression that
diff --git gcc/testsuite/g++.dg/cpp1y/constexpr-83116.C gcc/testsuite/g++.dg/cpp1y/constexpr-83116.C
index e69de29bb2d..18d79e2e1cc 100644
--- gcc/testsuite/g++.dg/cpp1y/constexpr-83116.C
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-83116.C
@@ -0,0 +1,18 @@
+// PR c++/83116
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+struct S {
+  constexpr S () : s(0) { foo (); }
+  constexpr int foo () { return s; }
+  int s;
+};
+
+int
+main ()
+{
+  static S var;
+  var.s = 5;
+  if (var.s != 5 || var.foo () != 5)
+    __builtin_abort ();
+}

	Marek



More information about the Gcc-patches mailing list