}
}
+/* 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
/* 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
--- /dev/null
+// 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, "");
--- /dev/null
+// 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());