diff --git a/infer/src/pulse/PulseModels.ml b/infer/src/pulse/PulseModels.ml
index 5eb81630d..340241558 100644
--- a/infer/src/pulse/PulseModels.ml
+++ b/infer/src/pulse/PulseModels.ml
@@ -969,6 +969,46 @@ module ProcNameDispatcher = struct
           $+...$--> Optional.value ~desc:"folly::Optional::value()"
         ; -"folly" &:: "Optional" &:: "value_or" $ capt_arg_payload $+ capt_arg_payload
           $+...$--> Optional.value_or ~desc:"folly::Optional::value_or()"
+          (* std::optional *)
+        ; -"std" &:: "optional" &:: "optional" $ capt_arg_payload
+          $+ any_arg_of_typ (-"std" &:: "nullopt_t")
+          $--> Optional.assign_none ~desc:"std::optional::optional(=nullopt)"
+        ; -"std" &:: "optional" &:: "optional" $ capt_arg_payload
+          $--> Optional.assign_none ~desc:"std::optional::optional()"
+        ; -"std" &:: "optional" &:: "optional" $ capt_arg_payload
+          $+ capt_arg_payload_of_typ (-"std" &:: "optional")
+          $--> Optional.assign_optional_value
+                 ~desc:"std::optional::optional(std::optional<Value> arg)"
+        ; -"std" &:: "optional" &:: "optional" $ capt_arg_payload $+ capt_arg_payload
+          $+...$--> Optional.assign_value ~desc:"std::optional::optional(Value arg)"
+        ; -"std" &:: "optional" &:: "operator=" <>$ capt_arg_payload
+          $+ any_arg_of_typ (-"std" &:: "nullopt_t")
+          $--> Optional.assign_none ~desc:"std::optional::operator=(None)"
+        ; -"std" &:: "optional" &:: "operator=" <>$ capt_arg_payload
+          $+ capt_arg_payload_of_typ (-"std" &:: "optional")
+          $--> Optional.assign_optional_value
+                 ~desc:"std::optional::operator=(std::optional<Value> arg)"
+        ; -"std" &:: "optional" &:: "operator=" <>$ capt_arg_payload $+ capt_arg_payload
+          $+...$--> Optional.assign_value ~desc:"std::optional::operator=(Value arg)"
+        ; -"std" &:: "optional" &:: "emplace<>" $ capt_arg_payload
+          $+...$--> Optional.emplace ~desc:"std::optional::emplace()"
+        ; -"std" &:: "optional" &:: "emplace" $ capt_arg_payload
+          $+...$--> Optional.emplace ~desc:"std::optional::emplace()"
+        ; -"std" &:: "optional" &:: "has_value" <>$ capt_arg_payload
+          $+...$--> Optional.has_value ~desc:"std::optional::has_value()"
+        ; -"std" &:: "optional" &:: "operator_bool" <>$ capt_arg_payload
+          $+...$--> Optional.has_value ~desc:"std::optional::operator_bool()"
+        ; -"std" &:: "optional" &:: "reset" <>$ capt_arg_payload
+          $+...$--> Optional.assign_none ~desc:"std::optional::reset()"
+        ; -"std" &:: "optional" &:: "value" <>$ capt_arg_payload
+          $+...$--> Optional.value ~desc:"std::optional::value()"
+        ; -"std" &:: "optional" &:: "operator*" <>$ capt_arg_payload
+          $+...$--> Optional.value ~desc:"std::optional::operator*()"
+        ; -"std" &:: "optional" &:: "operator->" <>$ capt_arg_payload
+          $+...$--> Optional.value ~desc:"std::optional::operator->()"
+        ; -"std" &:: "optional" &:: "value_or" $ capt_arg_payload $+ capt_arg_payload
+          $+...$--> Optional.value_or ~desc:"std::optional::value_or()"
+          (* end std::optional *)
         ; -"std" &:: "basic_string" &:: "data" <>$ capt_arg_payload $--> StdBasicString.data
         ; -"std" &:: "basic_string" &:: "~basic_string" <>$ capt_arg_payload
           $--> StdBasicString.destructor
diff --git a/infer/tests/codetoanalyze/cpp/pulse/issues.exp b/infer/tests/codetoanalyze/cpp/pulse/issues.exp
index 21d4ec34e..3304e3fc2 100644
--- a/infer/tests/codetoanalyze/cpp/pulse/issues.exp
+++ b/infer/tests/codetoanalyze/cpp/pulse/issues.exp
@@ -52,6 +52,13 @@ codetoanalyze/cpp/pulse/optional.cpp, none_copy_bad, 3, OPTIONAL_EMPTY_ACCESS, n
 codetoanalyze/cpp/pulse/optional.cpp, none_no_check_bad, 2, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),invalid access occurs here]
 codetoanalyze/cpp/pulse/optional.cpp, not_none_check_value_ok_FP, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),invalid access occurs here]
 codetoanalyze/cpp/pulse/optional.cpp, operator_arrow_bad, 0, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),when calling `emplace` here,parameter `state` of emplace,passed as argument to `folly::Optional<State>::operator->`,return from call to `folly::Optional<State>::operator->`,invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_assign2_bad, 4, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::operator=(None)` (modelled),return from call to `std::optional::operator=(None)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::operator=(None)` (modelled),return from call to `std::optional::operator=(None)` (modelled),invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_assign_bad, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),passed as argument to `std::optional::operator=(std::optional<Value> arg)` (modelled),return from call to `std::optional::operator=(std::optional<Value> arg)` (modelled),invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_none_copy_bad, 3, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),passed as argument to `std::optional::optional(std::optional<Value> arg)` (modelled),return from call to `std::optional::optional(std::optional<Value> arg)` (modelled),invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_none_no_check_bad, 2, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_not_none_check_value_ok_FP, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_operator_arrow_bad, 0, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),when calling `std_emplace` here,parameter `state` of std_emplace,passed as argument to `std::optional::operator->()` (modelled),return from call to `std::optional::operator->()` (modelled),invalid access occurs here]
+codetoanalyze/cpp/pulse/optional.cpp, std_value_or_check_value_ok_FP, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),invalid access occurs here]
 codetoanalyze/cpp/pulse/optional.cpp, test_trace_ref, 4, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `folly::Optional<int>::operator=` here,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional<int>::operator=`,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),return from call to `folly::Optional<int>::operator=`,invalid access occurs here]
 codetoanalyze/cpp/pulse/optional.cpp, value_or_check_value_ok_FP, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),invalid access occurs here]
 codetoanalyze/cpp/pulse/path.cpp, faulty_call_bad, 0, NULLPTR_DEREFERENCE, no_bucket, ERROR, [calling context starts here,in call to `only_bad_on_42_latent`,invalidation part of the trace starts here,when calling `may_return_null` here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,passed as argument to `may_return_null`,return from call to `may_return_null`,assigned,invalid access occurs here]
diff --git a/infer/tests/codetoanalyze/cpp/pulse/optional.cpp b/infer/tests/codetoanalyze/cpp/pulse/optional.cpp
index ba6715d08..f87f443fc 100644
--- a/infer/tests/codetoanalyze/cpp/pulse/optional.cpp
+++ b/infer/tests/codetoanalyze/cpp/pulse/optional.cpp
@@ -7,6 +7,7 @@
 
 #include <vector>
 #include <string>
+#include <optional>
 
 namespace folly {
 
@@ -185,3 +186,94 @@ struct StringWrapper {
 std::string get_optional_string_wrapper_ok() {
   return StringWrapper::get_optional().value().x.data();
 }
+
+int std_not_none_ok() {
+  std::optional<int> foo{5};
+  return foo.value();
+}
+
+int std_not_none_check_value_ok_FP() {
+  std::optional<int> foo{5};
+  int x = foo.value();
+  if (x != 5) {
+    std::optional<int> foo{std::nullopt};
+    return foo.value();
+  }
+  return x;
+}
+
+int std_none_check_ok() {
+  std::optional<int> foo{std::nullopt};
+  if (foo) {
+    return foo.value();
+  }
+  return -1;
+}
+
+int std_none_no_check_bad() {
+  std::optional<int> foo{std::nullopt};
+  return foo.value();
+}
+
+int std_none_copy_ok() {
+  std::optional<int> foo{5};
+  std::optional<int> bar{foo};
+  return bar.value();
+}
+
+int std_none_copy_bad() {
+  std::optional<int> foo{std::nullopt};
+  std::optional<int> bar{foo};
+  return bar.value();
+}
+
+int std_assign_ok() {
+  std::optional<int> foo{5};
+  std::optional<int> bar{foo};
+  foo = std::nullopt;
+  return bar.value();
+}
+
+int std_assign_bad() {
+  std::optional<int> foo{std::nullopt};
+  std::optional<int> bar{5};
+  int sum = bar.value();
+  bar = foo;
+  sum += bar.value();
+  return sum;
+}
+
+int std_assign2_bad() {
+  std::optional<int> foo{5};
+  int sum = foo.value();
+  foo = std::nullopt;
+  sum += foo.value();
+  return sum;
+}
+
+void std_emplace(std::optional<State> state) {
+  if (state) {
+    state.emplace();
+  }
+  auto pos = state->vec.begin();
+}
+
+void std_operator_arrow_bad() { std_emplace(std::nullopt); }
+
+int std_value_or_check_empty_ok() {
+  std::optional<int> foo{std::nullopt};
+  if (foo.value_or(0) > 0) {
+    return foo.value();
+  }
+  return -1;
+}
+
+int std_value_or_check_value_ok_FP() {
+  std::optional<int> foo{5};
+  int x = foo.value_or(0);
+  if (x != 5) {
+    std::optional<int> foo{std::nullopt};
+    return foo.value();
+  }
+  return -1;
+}