diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 42d00ec8d312d543ffe083c3b92bfe398cecc8a9..c8d9dae36fb32690946423f39257201f8f3e5446 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1555,6 +1555,32 @@ free_constructor (tree t)
     }
 }
 
+/* Helper function of cxx_bind_parameters_in_call.  Return non-NULL
+   if *TP is address of a static variable (or part of it) currently being
+   constructed or of a heap artificial variable.  */
+
+static tree
+addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data)
+{
+  if (TREE_CODE (*tp) == ADDR_EXPR)
+    if (tree var = get_base_address (TREE_OPERAND (*tp, 0)))
+      if (VAR_P (var) && TREE_STATIC (var))
+	{
+	  if (DECL_NAME (var) == heap_uninit_identifier
+	      || DECL_NAME (var) == heap_identifier
+	      || DECL_NAME (var) == heap_vec_uninit_identifier
+	      || DECL_NAME (var) == heap_vec_identifier)
+	    return var;
+
+	  constexpr_global_ctx *global = (constexpr_global_ctx *) data;
+	  if (global->values.get (var))
+	    return var;
+	}
+  if (TYPE_P (*tp))
+    *walk_subtrees = false;
+  return NULL_TREE;
+}
+
 /* Subroutine of cxx_eval_call_expression.
    We are processing a call expression (either CALL_EXPR or
    AGGR_INIT_EXPR) in the context of CTX.  Evaluate
@@ -1616,6 +1642,15 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 	    /* The destructor needs to see any modifications the callee makes
 	       to the argument.  */
 	    *non_constant_args = true;
+	    /* If arg is or contains address of a heap artificial variable or
+	       of a static variable being constructed, avoid caching the
+	       function call, as those variables might be modified by the
+	       function, or might be modified by the callers in between
+	       the cached function and just read by the function.  */
+	  else if (!*non_constant_args
+		   && cp_walk_tree (&arg, addr_of_non_const_var, ctx->global,
+				    NULL))
+	    *non_constant_args = true;
 
 	  /* For virtual calls, adjust the this argument, so that it is
 	     the object on which the method is called, rather than
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-99859-1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-99859-1.C
new file mode 100644
index 0000000000000000000000000000000000000000..dea5a5b56f807c556c4a0b108d4d7d47cf86c272
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-99859-1.C
@@ -0,0 +1,24 @@
+// PR c++/99859
+// { dg-do compile { target c++14 } }
+
+constexpr int
+foo (int *x)
+{
+  return ++*x;
+}
+
+struct S { constexpr S () : a(0) { foo (&a); foo (&a); } int a; };
+constexpr S s = S ();
+static_assert (s.a == 2, "");
+
+struct R { int *p; };
+
+constexpr int
+bar (R x)
+{
+  return ++*x.p;
+}
+
+struct T { int a = 0; constexpr T () { bar (R{&a}); bar (R{&a}); } };
+constexpr T t = T ();
+static_assert (t.a == 2, "");
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-99859-2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-99859-2.C
new file mode 100644
index 0000000000000000000000000000000000000000..a249f4746664c54b7cc5c7faebfc36e98564ec6c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-99859-2.C
@@ -0,0 +1,12 @@
+// PR c++/99859
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+  int i;
+  constexpr int f() { return i; }
+  constexpr A() : i(0) { i = f(); i = 1; i = f(); }
+};
+
+constexpr A a = A();
+static_assert (a.i == 1, "");
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new18.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new18.C
new file mode 100644
index 0000000000000000000000000000000000000000..24b298aafd45a002e06aebe4f00f63d9a434929e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new18.C
@@ -0,0 +1,45 @@
+// PR c++/99859
+// { dg-do compile { target c++20 } }
+
+template <class T>
+struct intrusive_ptr
+{
+  T *ptr = nullptr;
+  constexpr explicit intrusive_ptr(T* p) : ptr(p) {
+    ++ptr->count_;
+  }
+  constexpr ~intrusive_ptr() {
+    if (ptr->dec() == 0)
+      delete ptr;
+  }
+  constexpr intrusive_ptr(intrusive_ptr const& a) : ptr(a.ptr) {
+    ++ptr->count_;
+  }
+};
+
+struct Foo {
+  int count_ = 0;
+  constexpr int dec() {
+    return --count_;
+  }
+};
+
+constexpr bool baz() {
+  Foo f { 4 };
+  intrusive_ptr a(&f);
+  return true;
+}
+constexpr bool x = baz();
+
+constexpr void bar(intrusive_ptr<Foo> a) 
+{
+  if (a.ptr->count_ != 2) throw 1;
+}
+
+constexpr bool foo() {
+  intrusive_ptr a(new Foo());
+  bar(a);
+  return true;
+}
+
+static_assert(foo());
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new19.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new19.C
new file mode 100644
index 0000000000000000000000000000000000000000..7a73deed69310f4d934f88e62b955f55319c4a20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new19.C
@@ -0,0 +1,43 @@
+// PR c++/99859
+// { dg-do compile { target c++20 } }
+
+constexpr void
+foo (int *x)
+{
+  ++*x;
+}
+
+constexpr int
+bar ()
+{
+  int *x = new int (0);
+  foo (x);
+  foo (x);
+  int y = *x;
+  delete x;
+  return y;
+}
+
+static_assert (bar () == 2);
+
+struct R { int a, *b; };
+
+constexpr void
+baz (R x)
+{
+  ++*x.b;
+}
+
+constexpr int
+qux ()
+{
+  int *x = new int (0);
+  R r{1, x};
+  baz (r);
+  baz (r);
+  int y = *x;
+  delete x;
+  return y;
+}
+
+static_assert (qux () == 2);