diff --git a/tests/tactics.v b/tests/tactics.v
index 715e747db6d7b30ac1bbe2d91ac8c18709fcd2c7..b91a47339b2dab2a042a985aae239ad53ed6629e 100644
--- a/tests/tactics.v
+++ b/tests/tactics.v
@@ -55,6 +55,11 @@ Proof. intros ?. rename select nat into m. exists m. done. Qed.
 Goal ∀ (P : nat → Prop), P 3 → P 4 → P 4.
 Proof. intros P **. rename select (P _) into HP4. apply HP4. Qed.
 
+(** Regression tests for [naive_solver]. *)
+Lemma naive_solver_issue_115 (P : nat → Prop) (x : nat) :
+  (∀ x', P x' → x' = 10) → P x → x + 1 = 11.
+Proof. naive_solver. Qed.
+
 (** [mk_evar] works on things that coerce to types. *)
 (** This is a feature when we have packed structures, for example Iris's [ofe]
 (fields other than the carrier omitted). *)
@@ -63,7 +68,6 @@ Goal ∀ A : ofe, True.
 intros A.
 let x := mk_evar A in idtac.
 Abort.
-
 (** More surprisingly, it also works for other coercions into a
 universe, like [Is_true : bool → Prop]. *)
 Goal True.
diff --git a/theories/tactics.v b/theories/tactics.v
index d3910a89c7e524253793f239617aa8d8015b64d7..6ec949e0612abbc35a2c2ca994a7c028c850617f 100644
--- a/theories/tactics.v
+++ b/theories/tactics.v
@@ -222,8 +222,21 @@ current context.
 
 This is usually a more useful behavior than Coq's [evar], which is a
 side-effecting tactic (not returning anything) that introduces a local
-definition into the context that holds the evar. *)
-Ltac mk_evar T := open_constr:(_ : T).
+definition into the context that holds the evar.
+Note that the obvious alternative [open_constr (_:T)] has subtly different
+behavior, see std++ issue 115.
+
+Usually, Ltacs cannot return a value and have a side-effect, but we use the
+trick described at
+<https://stackoverflow.com/questions/45949064/check-for-evars-in-a-tactic-that-returns-a-value/46178884#46178884>
+to work around that: wrap the side-effect in a [match goal]. *)
+Ltac mk_evar T :=
+  let T := constr:(T : Type) in
+  let e := fresh in
+  let _ := match goal with _ => evar (e:T) end in
+  let e' := eval unfold e in e in
+  let _ := match goal with _ => clear e end in
+  e'.
 
 (** The tactic [eunify x y] succeeds if [x] and [y] can be unified, and fails
 otherwise. If it succeeds, it will instantiate necessary evars in [x] and [y].