diff --git a/.clang-format-ignore b/.clang-format-ignore
index bf05754242f..7d2a397c6b3 100644
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,4 +1,3 @@
 jbmc/src/miniz/miniz.cpp
 src/cprover/wcwidth.c
-src/nonstd/optional.hpp
 unit/catch/catch.hpp
diff --git a/jbmc/src/janalyzer/janalyzer_parse_options.cpp b/jbmc/src/janalyzer/janalyzer_parse_options.cpp
index 0b3eee5c96c..ad856986c4a 100644
--- a/jbmc/src/janalyzer/janalyzer_parse_options.cpp
+++ b/jbmc/src/janalyzer/janalyzer_parse_options.cpp
@@ -445,7 +445,7 @@ int janalyzer_parse_optionst::perform_analysis(
     }
     else
     {
-      optionalt<std::string> json_file;
+      std::optional<std::string> json_file;
       if(cmdline.isset("json"))
         json_file = cmdline.get_value("json");
       bool result = taint_analysis(
diff --git a/jbmc/src/java_bytecode/README.md b/jbmc/src/java_bytecode/README.md
index ccb0445f864..f7593c2a23e 100644
--- a/jbmc/src/java_bytecode/README.md
+++ b/jbmc/src/java_bytecode/README.md
@@ -677,7 +677,7 @@ used. Under eager loading
 \ref java_bytecode_languaget::convert_single_method(const irep_idt &, symbol_table_baset &, lazy_class_to_declared_symbols_mapt &, message_handlert &)
 is called once for each method listed in method_bytecode (described above). This
 then calls
-\ref java_bytecode_languaget::convert_single_method(const irep_idt &, symbol_table_baset &, optionalt<ci_lazy_methods_neededt>, lazy_class_to_declared_symbols_mapt &, message_handlert &);
+\ref java_bytecode_languaget::convert_single_method(const irep_idt &, symbol_table_baset &, std::optional<ci_lazy_methods_neededt>, lazy_class_to_declared_symbols_mapt &, message_handlert &);
 
 without a ci_lazy_methods_neededt object, which calls
 \ref java_bytecode_convert_method, passing in the method parse tree. This in
diff --git a/jbmc/src/java_bytecode/assignments_from_json.cpp b/jbmc/src/java_bytecode/assignments_from_json.cpp
index 223f5a5187e..f9e7a075807 100644
--- a/jbmc/src/java_bytecode/assignments_from_json.cpp
+++ b/jbmc/src/java_bytecode/assignments_from_json.cpp
@@ -44,7 +44,7 @@ struct object_creation_infot
 
   /// Where runtime types differ from compile-time types, we need to mark the
   /// runtime types as needed by lazy methods.
-  optionalt<ci_lazy_methods_neededt> &needed_lazy_methods;
+  std::optional<ci_lazy_methods_neededt> &needed_lazy_methods;
 
   /// Map to keep track of reference-equal objects. Each entry has an ID (such
   /// that any two reference-equal objects have the same ID) and the expression
@@ -117,7 +117,7 @@ static bool is_enum_with_type_equal_to_declaring_type(
 /// A runtime type that is different from the objects compile-time type should
 /// be specified in `json` in this way.
 /// Type values are of the format "my.package.name.ClassName".
-static optionalt<std::string> get_type(const jsont &json)
+static std::optional<std::string> get_type(const jsont &json)
 {
   if(!json.is_object())
     return {};
@@ -267,9 +267,9 @@ static jsont get_untyped_string(const jsont &json)
 /// \param symbol_table: used to look up the type given its name.
 /// \return runtime type of the object, if specified by at least one of the
 ///   parameters.
-static optionalt<java_class_typet> runtime_type(
+static std::optional<java_class_typet> runtime_type(
   const jsont &json,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   const symbol_table_baset &symbol_table)
 {
   const auto type_from_json = get_type(json);
@@ -304,9 +304,9 @@ static optionalt<java_class_typet> runtime_type(
 ///   field, this takes priority over \p type_from_array.
 /// \param type_from_array: may contain a type name from a containing array.
 /// \return if the type of an array was given, the type of its elements.
-static optionalt<std::string> element_type_from_array_type(
+static std::optional<std::string> element_type_from_array_type(
   const jsont &json,
-  const optionalt<std::string> &type_from_array)
+  const std::optional<std::string> &type_from_array)
 {
   if(const auto json_array_type = get_type(json))
   {
@@ -332,7 +332,7 @@ static optionalt<std::string> element_type_from_array_type(
 code_with_references_listt assign_from_json_rec(
   const exprt &expr,
   const jsont &json,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   object_creation_infot &info);
 
 /// One of the base cases (primitive case) of the recursion.
@@ -392,7 +392,7 @@ static code_frontend_assignt assign_null(const exprt &expr)
 static code_with_references_listt assign_array_data_component_from_json(
   const exprt &expr,
   const jsont &json,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   object_creation_infot &info)
 {
   const auto &java_class_type = followed_class_type(expr, info.symbol_table);
@@ -411,7 +411,7 @@ static code_with_references_listt assign_array_data_component_from_json(
     code_frontend_assignt{array_init_data, data_member_expr, info.loc});
 
   size_t index = 0;
-  const optionalt<std::string> inferred_element_type =
+  const std::optional<std::string> inferred_element_type =
     element_type_from_array_type(json, type_from_array);
   const json_arrayt json_array = get_untyped_array(json, element_type);
   for(auto it = json_array.begin(); it < json_array.end(); it++, index++)
@@ -457,7 +457,7 @@ static std::pair<code_with_references_listt, exprt>
 assign_det_length_array_from_json(
   const exprt &expr,
   const jsont &json,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   object_creation_infot &info)
 {
   PRECONDITION(is_java_array_type(expr.type()));
@@ -486,7 +486,7 @@ static code_with_references_listt assign_nondet_length_array_from_json(
   const exprt &array,
   const jsont &json,
   const exprt &given_length_expr,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   object_creation_infot &info)
 {
   PRECONDITION(is_java_array_type(array.type()));
@@ -793,7 +793,7 @@ static get_or_create_reference_resultt get_or_create_reference(
 static code_with_references_listt assign_reference_from_json(
   const exprt &expr,
   const jsont &json,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   object_creation_infot &info)
 {
   const std::string &id = has_enum_type(expr, info.symbol_table)
@@ -849,7 +849,7 @@ static code_with_references_listt assign_reference_from_json(
 code_with_references_listt assign_from_json_rec(
   const exprt &expr,
   const jsont &json,
-  const optionalt<std::string> &type_from_array,
+  const std::optional<std::string> &type_from_array,
   object_creation_infot &info)
 {
   code_with_references_listt result;
@@ -915,7 +915,7 @@ code_with_references_listt assign_from_json(
   const jsont &json,
   const irep_idt &function_id,
   symbol_table_baset &symbol_table,
-  optionalt<ci_lazy_methods_neededt> &needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> &needed_lazy_methods,
   size_t max_user_array_length,
   std::unordered_map<std::string, object_creation_referencet> &references)
 {
diff --git a/jbmc/src/java_bytecode/assignments_from_json.h b/jbmc/src/java_bytecode/assignments_from_json.h
index 160ba4590f0..328fbb5c9b4 100644
--- a/jbmc/src/java_bytecode/assignments_from_json.h
+++ b/jbmc/src/java_bytecode/assignments_from_json.h
@@ -100,7 +100,7 @@ code_with_references_listt assign_from_json(
   const jsont &json,
   const irep_idt &function_id,
   symbol_table_baset &symbol_table,
-  optionalt<ci_lazy_methods_neededt> &needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> &needed_lazy_methods,
   size_t max_user_array_length,
   std::unordered_map<std::string, object_creation_referencet> &references);
 
diff --git a/jbmc/src/java_bytecode/ci_lazy_methods.h b/jbmc/src/java_bytecode/ci_lazy_methods.h
index d96174aec39..f37e153589e 100644
--- a/jbmc/src/java_bytecode/ci_lazy_methods.h
+++ b/jbmc/src/java_bytecode/ci_lazy_methods.h
@@ -41,7 +41,8 @@ class method_bytecodet
     const java_bytecode_parse_treet::methodt &method;
   };
 
-  typedef optionalt<std::reference_wrapper<const class_method_and_bytecodet>>
+  typedef std::optional<
+    std::reference_wrapper<const class_method_and_bytecodet>>
     opt_reft;
 
 private:
diff --git a/jbmc/src/java_bytecode/ci_lazy_methods_needed.cpp b/jbmc/src/java_bytecode/ci_lazy_methods_needed.cpp
index 72964181f4d..11d5c7dac59 100644
--- a/jbmc/src/java_bytecode/ci_lazy_methods_needed.cpp
+++ b/jbmc/src/java_bytecode/ci_lazy_methods_needed.cpp
@@ -53,7 +53,7 @@ void ci_lazy_methods_neededt::add_cprover_nondet_initialize_if_it_exists(
   const irep_idt &class_id)
 {
   resolve_inherited_componentt resolve_inherited_component{symbol_table};
-  optionalt<resolve_inherited_componentt::inherited_componentt>
+  std::optional<resolve_inherited_componentt::inherited_componentt>
     cprover_nondet_initialize = resolve_inherited_component(
       class_id, "cproverNondetInitialize:()V", true);
 
diff --git a/jbmc/src/java_bytecode/code_with_references.h b/jbmc/src/java_bytecode/code_with_references.h
index ba775f88ada..6f38b69f093 100644
--- a/jbmc/src/java_bytecode/code_with_references.h
+++ b/jbmc/src/java_bytecode/code_with_references.h
@@ -30,7 +30,7 @@ struct object_creation_referencet
   /// This should only be set once the actual elements of the array have been
   /// seen, not the first time an `@ref` have been seen, only when `@id` is
   /// seen.
-  optionalt<exprt> array_length;
+  std::optional<exprt> array_length;
 };
 
 /// Base class for code which can contain references which can get replaced
diff --git a/jbmc/src/java_bytecode/generic_parameter_specialization_map.cpp b/jbmc/src/java_bytecode/generic_parameter_specialization_map.cpp
index 39033edf2ad..5444a6f11f7 100644
--- a/jbmc/src/java_bytecode/generic_parameter_specialization_map.cpp
+++ b/jbmc/src/java_bytecode/generic_parameter_specialization_map.cpp
@@ -51,7 +51,7 @@ void generic_parameter_specialization_mapt::pop(std::size_t container_index)
   container_to_specializations.at(container_index).pop();
 }
 
-optionalt<reference_typet>
+std::optional<reference_typet>
 generic_parameter_specialization_mapt::pop(const irep_idt &parameter_name)
 {
   const auto types_it = param_to_container.find(parameter_name);
diff --git a/jbmc/src/java_bytecode/generic_parameter_specialization_map.h b/jbmc/src/java_bytecode/generic_parameter_specialization_map.h
index 914dca2758b..2a954e11e66 100644
--- a/jbmc/src/java_bytecode/generic_parameter_specialization_map.h
+++ b/jbmc/src/java_bytecode/generic_parameter_specialization_map.h
@@ -53,8 +53,8 @@ class generic_parameter_specialization_mapt
   /// a given type parameter
   /// \param parameter_name: The name of the type parameter
   /// \returns: The specialization for the given type parameter, if there was
-  ///   one before the pop, or an empty optionalt if the stack was empty
-  optionalt<reference_typet> pop(const irep_idt &parameter_name);
+  ///   one before the pop, or an empty std::optional if the stack was empty
+  std::optional<reference_typet> pop(const irep_idt &parameter_name);
 
   /// A wrapper for a generic_parameter_specialization_mapt and a namespacet
   /// that can be output to a stream
diff --git a/jbmc/src/java_bytecode/generic_parameter_specialization_map_keys.h b/jbmc/src/java_bytecode/generic_parameter_specialization_map_keys.h
index f8f9f8dd8d8..bd1eaa79cc8 100644
--- a/jbmc/src/java_bytecode/generic_parameter_specialization_map_keys.h
+++ b/jbmc/src/java_bytecode/generic_parameter_specialization_map_keys.h
@@ -17,7 +17,7 @@ class generic_parameter_specialization_map_keyst
   /// Generic parameter specialization map to modify
   generic_parameter_specialization_mapt &generic_parameter_specialization_map;
   /// Key of the container to pop on destruction
-  optionalt<std::size_t> container_id;
+  std::optional<std::size_t> container_id;
 
 public:
   /// Initialize a generic-parameter-specialization-map entry owner operating
diff --git a/jbmc/src/java_bytecode/jar_file.cpp b/jbmc/src/java_bytecode/jar_file.cpp
index e4f29bece5c..0cab9589216 100644
--- a/jbmc/src/java_bytecode/jar_file.cpp
+++ b/jbmc/src/java_bytecode/jar_file.cpp
@@ -54,7 +54,7 @@ jar_filet &jar_filet::operator=(jar_filet &&other)
   return *this;
 }
 
-optionalt<std::string> jar_filet::get_entry(const std::string &name)
+std::optional<std::string> jar_filet::get_entry(const std::string &name)
 {
   const auto entry=m_name_to_index.find(name);
   if(entry==m_name_to_index.end())
diff --git a/jbmc/src/java_bytecode/jar_file.h b/jbmc/src/java_bytecode/jar_file.h
index bf6a1d02a0b..046f4f372ad 100644
--- a/jbmc/src/java_bytecode/jar_file.h
+++ b/jbmc/src/java_bytecode/jar_file.h
@@ -9,14 +9,13 @@ Author: Diffblue Ltd
 #ifndef CPROVER_JAVA_BYTECODE_JAR_FILE_H
 #define CPROVER_JAVA_BYTECODE_JAR_FILE_H
 
-#include <unordered_map>
+#include "mz_zip_archive.h"
+
+#include <optional>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
-#include <util/optional.h>
-
-#include "mz_zip_archive.h"
-
 /// Class representing a .jar archive. Uses miniz to decompress and index
 /// archive.
 class jar_filet final
@@ -42,7 +41,7 @@ class jar_filet final
   /// Get contents of a file in the jar archive.
   /// Returns nullopt if file doesn't exist.
   /// \param filename: Name of the file in the archive
-  optionalt<std::string> get_entry(const std::string &filename);
+  std::optional<std::string> get_entry(const std::string &filename);
 
   /// Get contents of the Manifest file in the jar archive as a key-value map
   /// (both as strings)
diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_class.cpp b/jbmc/src/java_bytecode/java_bytecode_convert_class.cpp
index d14a070e506..f600348b943 100644
--- a/jbmc/src/java_bytecode/java_bytecode_convert_class.cpp
+++ b/jbmc/src/java_bytecode/java_bytecode_convert_class.cpp
@@ -186,8 +186,8 @@ class java_bytecode_convert_classt
 /// \param signature: Signature of the class
 /// \return Reference of the generic superclass, or empty if the superclass
 ///   is not generic
-static optionalt<std::string>
-extract_generic_superclass_reference(const optionalt<std::string> &signature)
+static std::optional<std::string> extract_generic_superclass_reference(
+  const std::optional<std::string> &signature)
 {
   if(signature.has_value())
   {
@@ -226,8 +226,8 @@ extract_generic_superclass_reference(const optionalt<std::string> &signature)
 /// \param interface_name: The interface name
 /// \return Reference of the generic interface, or empty if the interface
 ///   is not generic
-static optionalt<std::string> extract_generic_interface_reference(
-  const optionalt<std::string> &signature,
+static std::optional<std::string> extract_generic_interface_reference(
+  const std::optional<std::string> &signature,
   const std::string &interface_name)
 {
   if(signature.has_value())
@@ -355,7 +355,7 @@ void java_bytecode_convert_classt::convert(
     // including the generic info in its signature
     // e.g., signature for class 'A<T>' that extends
     // 'Generic<Integer>' is '<T:Ljava/lang/Object;>LGeneric<LInteger;>;'
-    const optionalt<std::string> &superclass_ref =
+    const std::optional<std::string> &superclass_ref =
       extract_generic_superclass_reference(c.signature);
     if(superclass_ref.has_value())
     {
@@ -397,7 +397,7 @@ void java_bytecode_convert_classt::convert(
     // including the generic info in its signature
     // e.g., signature for class 'A implements GenericInterface<Integer>' is
     // 'Ljava/lang/Object;LGenericInterface<LInteger;>;'
-    const optionalt<std::string> interface_ref =
+    const std::optional<std::string> interface_ref =
       extract_generic_interface_reference(c.signature, id2string(interface));
     if(interface_ref.has_value())
     {
diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp b/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp
index 2416188aa0d..758bcdf6ec8 100644
--- a/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp
+++ b/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp
@@ -228,7 +228,7 @@ exprt java_bytecode_convert_methodt::variable(
 /// \return the constructed member type
 java_method_typet member_type_lazy(
   const std::string &descriptor,
-  const optionalt<std::string> &signature,
+  const std::optional<std::string> &signature,
   const std::string &class_name,
   const std::string &method_name,
   message_handlert &message_handler)
@@ -534,7 +534,7 @@ void create_parameter_symbols(
 void java_bytecode_convert_methodt::convert(
   const symbolt &class_symbol,
   const methodt &m,
-  const optionalt<prefix_filtert> &method_context)
+  const std::optional<prefix_filtert> &method_context)
 {
   // Construct the fully qualified method name
   // (e.g. "my.package.ClassName.myMethodName:(II)I") and query the symbol table
@@ -1263,7 +1263,7 @@ java_bytecode_convert_methodt::convert_instructions(const methodt &method)
       }
     }
 
-    optionalt<codet> catch_instruction;
+    std::optional<codet> catch_instruction;
 
     if(catch_type!=typet())
     {
@@ -3083,7 +3083,7 @@ code_blockt java_bytecode_convert_methodt::convert_astore(
   return block;
 }
 
-optionalt<exprt> java_bytecode_convert_methodt::convert_invoke_dynamic(
+std::optional<exprt> java_bytecode_convert_methodt::convert_invoke_dynamic(
   const source_locationt &location,
   std::size_t instruction_address,
   const exprt &arg0,
@@ -3282,11 +3282,11 @@ void java_bytecode_convert_method(
   message_handlert &message_handler,
   size_t max_array_length,
   bool throw_assertion_error,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
   java_string_library_preprocesst &string_preprocess,
   const class_hierarchyt &class_hierarchy,
   bool threading_support,
-  const optionalt<prefix_filtert> &method_context,
+  const std::optional<prefix_filtert> &method_context,
   bool assert_no_exceptions_thrown)
 
 {
diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_method.h b/jbmc/src/java_bytecode/java_bytecode_convert_method.h
index e9a0fe01742..8ad5d25ad96 100644
--- a/jbmc/src/java_bytecode/java_bytecode_convert_method.h
+++ b/jbmc/src/java_bytecode/java_bytecode_convert_method.h
@@ -31,11 +31,11 @@ void java_bytecode_convert_method(
   message_handlert &message_handler,
   size_t max_array_length,
   bool throw_assertion_error,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
   java_string_library_preprocesst &string_preprocess,
   const class_hierarchyt &class_hierarchy,
   bool threading_support,
-  const optionalt<prefix_filtert> &method_context,
+  const std::optional<prefix_filtert> &method_context,
   bool assert_no_exceptions_thrown);
 
 void create_method_stub_symbol(
diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h b/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h
index 011b0ff205c..2d12b5377bd 100644
--- a/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h
+++ b/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h
@@ -40,7 +40,7 @@ class java_bytecode_convert_methodt
     message_handlert &_message_handler,
     size_t _max_array_length,
     bool throw_assertion_error,
-    optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+    std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
     java_string_library_preprocesst &_string_preprocess,
     const class_hierarchyt &class_hierarchy,
     bool threading_support,
@@ -69,7 +69,7 @@ class java_bytecode_convert_methodt
   void operator()(
     const symbolt &class_symbol,
     const methodt &method,
-    const optionalt<prefix_filtert> &method_context)
+    const std::optional<prefix_filtert> &method_context)
   {
     convert(class_symbol, method, method_context);
   }
@@ -84,7 +84,7 @@ class java_bytecode_convert_methodt
   const bool throw_assertion_error;
   const bool assert_no_exceptions_thrown;
   const bool threading_support;
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods;
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods;
 
   /// Fully qualified name of the method under translation.
   /// Initialized by `convert`.
@@ -319,7 +319,7 @@ class java_bytecode_convert_methodt
   void convert(
     const symbolt &class_symbol,
     const methodt &,
-    const optionalt<prefix_filtert> &method_context);
+    const std::optional<prefix_filtert> &method_context);
 
   code_blockt convert_parameter_annotations(
     const methodt &method,
@@ -368,7 +368,7 @@ class java_bytecode_convert_methodt
       std::vector<java_bytecode_parse_treet::instructiont>::const_iterator>
       &ret_instructions) const;
 
-  optionalt<exprt> convert_invoke_dynamic(
+  std::optional<exprt> convert_invoke_dynamic(
     const source_locationt &location,
     std::size_t instruction_address,
     const exprt &arg0,
diff --git a/jbmc/src/java_bytecode/java_bytecode_instrument.cpp b/jbmc/src/java_bytecode/java_bytecode_instrument.cpp
index 9c908a29a72..a37d6688be9 100644
--- a/jbmc/src/java_bytecode/java_bytecode_instrument.cpp
+++ b/jbmc/src/java_bytecode/java_bytecode_instrument.cpp
@@ -71,7 +71,7 @@ class java_bytecode_instrumentt
   void instrument_code(codet &code);
   void add_expr_instrumentation(code_blockt &block, const exprt &expr);
   void prepend_instrumentation(codet &code, code_blockt &instrumentation);
-  optionalt<codet> instrument_expr(const exprt &expr);
+  std::optional<codet> instrument_expr(const exprt &expr);
 };
 
 const std::vector<std::string> exception_needed_classes = {
@@ -218,7 +218,7 @@ code_ifthenelset java_bytecode_instrumentt::check_class_cast(
   pointer_typet voidptr = pointer_type(java_void_type());
   exprt null_check_op = typecast_exprt::conditional_cast(tested_expr, voidptr);
 
-  optionalt<codet> check_code;
+  std::optional<codet> check_code;
   if(throw_runtime_exceptions)
   {
     check_code=
@@ -309,7 +309,7 @@ void java_bytecode_instrumentt::add_expr_instrumentation(
   code_blockt &block,
   const exprt &expr)
 {
-  if(optionalt<codet> expr_instrumentation = instrument_expr(expr))
+  if(std::optional<codet> expr_instrumentation = instrument_expr(expr))
   {
     if(expr_instrumentation->get_statement() == ID_block)
       block.append(to_code_block(*expr_instrumentation));
@@ -447,13 +447,14 @@ void java_bytecode_instrumentt::instrument_code(codet &code)
 /// either assertions or runtime exceptions.
 /// \param expr: the expression for which we compute instrumentation
 /// \return The instrumentation for \p expr if required
-optionalt<codet> java_bytecode_instrumentt::instrument_expr(const exprt &expr)
+std::optional<codet>
+java_bytecode_instrumentt::instrument_expr(const exprt &expr)
 {
   code_blockt result;
   // First check our operands:
   for(const auto &op : expr.operands())
   {
-    if(optionalt<codet> op_result = instrument_expr(op))
+    if(std::optional<codet> op_result = instrument_expr(op))
       result.add(std::move(*op_result));
   }
 
diff --git a/jbmc/src/java_bytecode/java_bytecode_language.cpp b/jbmc/src/java_bytecode/java_bytecode_language.cpp
index ae1acc79f91..32d870c0494 100644
--- a/jbmc/src/java_bytecode/java_bytecode_language.cpp
+++ b/jbmc/src/java_bytecode/java_bytecode_language.cpp
@@ -1238,7 +1238,7 @@ void java_bytecode_languaget::convert_lazy_method(
 ///   be called for each function call in `function_body`.
 static void notify_static_method_calls(
   const codet &function_body,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods)
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods)
 {
   if(needed_lazy_methods)
   {
@@ -1295,7 +1295,7 @@ static void notify_static_method_calls(
 bool java_bytecode_languaget::convert_single_method(
   const irep_idt &function_id,
   symbol_table_baset &symbol_table,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
   lazy_class_to_declared_symbols_mapt &class_to_declared_symbols,
   message_handlert &message_handler)
 {
@@ -1354,7 +1354,7 @@ bool java_bytecode_languaget::convert_single_method(
 bool java_bytecode_languaget::convert_single_method_code(
   const irep_idt &function_id,
   symbol_table_baset &symbol_table,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
   lazy_class_to_declared_symbols_mapt &class_to_declared_symbols,
   message_handlert &message_handler)
 {
diff --git a/jbmc/src/java_bytecode/java_bytecode_language.h b/jbmc/src/java_bytecode/java_bytecode_language.h
index 9bf89d5b025..b2f7c95cbe3 100644
--- a/jbmc/src/java_bytecode/java_bytecode_language.h
+++ b/jbmc/src/java_bytecode/java_bytecode_language.h
@@ -229,7 +229,7 @@ struct java_bytecode_language_optionst
   /// JSON which contains initial values of static fields (right
   /// after the static initializer of the class was run). This is read from the
   /// file specified by the --static-values command-line option.
-  optionalt<json_objectt> static_values_json;
+  std::optional<json_objectt> static_values_json;
 
   /// List of classes to never load
   std::unordered_set<std::string> no_load_classes;
@@ -243,7 +243,7 @@ struct java_bytecode_language_optionst
   /// symbol (corresponding to the body of the method) will be replaced with the
   /// same kind of "return nondet null or instance of return type" body that we
   /// use for stubbed methods. The original method body will never be loaded.
-  optionalt<prefix_filtert> method_context;
+  std::optional<prefix_filtert> method_context;
 
   /// Should we lift clinit calls in function bodies to the top? For example,
   /// turning `if(x) A.clinit() else B.clinit()` into
@@ -251,7 +251,7 @@ struct java_bytecode_language_optionst
   bool should_lift_clinit_calls;
 
   /// If set then a JAR file has been given via the -jar option.
-  optionalt<std::string> main_jar;
+  std::optional<std::string> main_jar;
 };
 
 #define JAVA_CLASS_MODEL_SUFFIX "@class_model"
@@ -349,27 +349,27 @@ class java_bytecode_languaget:public languaget
     convert_single_method(
       function_id,
       symbol_table,
-      optionalt<ci_lazy_methods_neededt>(),
+      std::optional<ci_lazy_methods_neededt>(),
       class_to_declared_symbols,
       message_handler);
   }
   bool convert_single_method(
     const irep_idt &function_id,
     symbol_table_baset &symbol_table,
-    optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+    std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
     lazy_class_to_declared_symbols_mapt &class_to_declared_symbols,
     message_handlert &);
   bool convert_single_method_code(
     const irep_idt &function_id,
     symbol_table_baset &symbol_table,
-    optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+    std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
     lazy_class_to_declared_symbols_mapt &class_to_declared_symbols,
     message_handlert &);
 
   bool do_ci_lazy_method_conversion(symbol_table_baset &, message_handlert &);
   const select_pointer_typet &get_pointer_type_selector() const;
 
-  optionalt<java_bytecode_language_optionst> language_options;
+  std::optional<java_bytecode_language_optionst> language_options;
   irep_idt main_class;
   std::vector<irep_idt> main_jar_classes;
   java_class_loadert java_class_loader;
diff --git a/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp b/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp
index cb593a66dbe..3aa3449e4c6 100644
--- a/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp
+++ b/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp
@@ -90,8 +90,8 @@ void java_bytecode_parse_treet::annotationt::element_value_pairt::output(
 /// \param annotation_type_name: An irep_idt representing the name of the
 ///   annotation class, e.g. java::java.lang.SuppressWarnings
 /// \return The first annotation with the given name in annotations if one
-///   exists, an empty optionalt otherwise.
-optionalt<java_bytecode_parse_treet::annotationt>
+///   exists, an empty std::optional otherwise.
+std::optional<java_bytecode_parse_treet::annotationt>
 java_bytecode_parse_treet::find_annotation(
   const annotationst &annotations,
   const irep_idt &annotation_type_name)
diff --git a/jbmc/src/java_bytecode/java_bytecode_parse_tree.h b/jbmc/src/java_bytecode/java_bytecode_parse_tree.h
index 5d649009c1a..0af9819055c 100644
--- a/jbmc/src/java_bytecode/java_bytecode_parse_tree.h
+++ b/jbmc/src/java_bytecode/java_bytecode_parse_tree.h
@@ -13,7 +13,6 @@ Author: Daniel Kroening, kroening@kroening.com
 #include <set>
 #include <map>
 
-#include <util/optional.h>
 #include <util/std_types.h>
 
 #include "bytecode_info.h"
@@ -48,7 +47,7 @@ struct java_bytecode_parse_treet
 
   typedef std::vector<annotationt> annotationst;
 
-  static optionalt<annotationt> find_annotation(
+  static std::optional<annotationt> find_annotation(
     const annotationst &annotations,
     const irep_idt &annotation_type_name);
 
@@ -64,7 +63,7 @@ struct java_bytecode_parse_treet
   struct membert
   {
     std::string descriptor;
-    optionalt<std::string> signature;
+    std::optional<std::string> signature;
     irep_idt name;
     bool is_public, is_protected, is_private, is_static, is_final;
     annotationst annotations;
@@ -127,7 +126,7 @@ struct java_bytecode_parse_treet
     {
       irep_idt name;
       std::string descriptor;
-      optionalt<std::string> signature;
+      std::optional<std::string> signature;
       std::size_t index;
       std::size_t start_pc;
       std::size_t length;
@@ -228,7 +227,7 @@ struct java_bytecode_parse_treet
     struct lambda_method_handlet
     {
       java_class_typet::method_handle_kindt handle_type;
-      optionalt<class_method_descriptor_exprt> method_descriptor;
+      std::optional<class_method_descriptor_exprt> method_descriptor;
 
       /// Construct a lambda method handle with parameters \p params.
       lambda_method_handlet(
@@ -273,7 +272,7 @@ struct java_bytecode_parse_treet
 
     typedef std::list<irep_idt> implementst;
     implementst implements;
-    optionalt<std::string> signature;
+    std::optional<std::string> signature;
     typedef std::list<fieldt> fieldst;
     typedef std::list<methodt> methodst;
     fieldst fields;
diff --git a/jbmc/src/java_bytecode/java_bytecode_parser.cpp b/jbmc/src/java_bytecode/java_bytecode_parser.cpp
index c9992832609..b7e02ddd859 100644
--- a/jbmc/src/java_bytecode/java_bytecode_parser.cpp
+++ b/jbmc/src/java_bytecode/java_bytecode_parser.cpp
@@ -109,7 +109,7 @@ class java_bytecode_parsert final : public parsert
   void get_annotation_class_refs(const std::vector<annotationt> &annotations);
   void get_annotation_value_class_refs(const exprt &value);
   void parse_local_variable_type_table(methodt &method);
-  optionalt<lambda_method_handlet>
+  std::optional<lambda_method_handlet>
   parse_method_handle(const class method_handle_infot &entry);
   void read_bootstrapmethods_entry();
 
@@ -1803,7 +1803,7 @@ void java_bytecode_parsert::rmethod()
     rmethod_attribute(method);
 }
 
-optionalt<java_bytecode_parse_treet> java_bytecode_parse(
+std::optional<java_bytecode_parse_treet> java_bytecode_parse(
   std::istream &istream,
   const irep_idt &class_name,
   message_handlert &message_handler,
@@ -1825,7 +1825,7 @@ optionalt<java_bytecode_parse_treet> java_bytecode_parse(
   return std::move(java_bytecode_parser.parse_tree);
 }
 
-optionalt<java_bytecode_parse_treet> java_bytecode_parse(
+std::optional<java_bytecode_parse_treet> java_bytecode_parse(
   const std::string &file,
   const irep_idt &class_name,
   message_handlert &message_handler,
@@ -1914,7 +1914,7 @@ static java_class_typet::method_handle_kindt get_method_handle_type(
 /// \param entry: the constant pool entry of the methodhandle_info structure
 /// \return the method_handle type of the methodhandle_structure,
 ///   either for a recognized bootstrap method or for a lambda function
-optionalt<java_bytecode_parsert::lambda_method_handlet>
+std::optional<java_bytecode_parsert::lambda_method_handlet>
 java_bytecode_parsert::parse_method_handle(const method_handle_infot &entry)
 {
   const std::function<pool_entryt &(u2)> pool_entry_lambda =
@@ -2071,7 +2071,7 @@ void java_bytecode_parsert::read_bootstrapmethods_entry()
     }
 
     log.debug() << "INFO: parse lambda handle" << messaget::eom;
-    optionalt<lambda_method_handlet> lambda_method_handle =
+    std::optional<lambda_method_handlet> lambda_method_handle =
       parse_method_handle(method_handle_infot{method_handle_argument});
 
     if(!lambda_method_handle.has_value())
diff --git a/jbmc/src/java_bytecode/java_bytecode_parser.h b/jbmc/src/java_bytecode/java_bytecode_parser.h
index af456ffba3d..9150428b686 100644
--- a/jbmc/src/java_bytecode/java_bytecode_parser.h
+++ b/jbmc/src/java_bytecode/java_bytecode_parser.h
@@ -10,10 +10,11 @@ Author: Daniel Kroening, kroening@kroening.com
 #ifndef CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_PARSER_H
 #define CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_PARSER_H
 
+#include <util/irep.h>
+
 #include <iosfwd>
+#include <optional>
 #include <string>
-#include <util/irep.h>
-#include <util/optional.h>
 
 struct java_bytecode_parse_treet;
 
@@ -23,8 +24,8 @@ struct java_bytecode_parse_treet;
 /// \param msg: handles log messages
 /// \param skip_instructions: if true, the loaded class's methods will all be
 ///   empty. Saves time and memory for consumers that only want signature info.
-/// \return parse tree, or empty optionalt on failure
-optionalt<java_bytecode_parse_treet> java_bytecode_parse(
+/// \return parse tree, or empty std::optional on failure
+std::optional<java_bytecode_parse_treet> java_bytecode_parse(
   const std::string &file,
   const irep_idt &class_name,
   class message_handlert &msg,
@@ -36,8 +37,8 @@ optionalt<java_bytecode_parse_treet> java_bytecode_parse(
 /// \param msg: handles log messages
 /// \param skip_instructions: if true, the loaded class's methods will all be
 ///   empty. Saves time and memory for consumers that only want signature info.
-/// \return parse tree, or empty optionalt on failure
-optionalt<java_bytecode_parse_treet> java_bytecode_parse(
+/// \return parse tree, or empty std::optional on failure
+std::optional<java_bytecode_parse_treet> java_bytecode_parse(
   std::istream &stream,
   const irep_idt &class_name,
   class message_handlert &msg,
diff --git a/jbmc/src/java_bytecode/java_class_loader.cpp b/jbmc/src/java_bytecode/java_class_loader.cpp
index 11eb97cba65..19b0c698d31 100644
--- a/jbmc/src/java_bytecode/java_class_loader.cpp
+++ b/jbmc/src/java_bytecode/java_class_loader.cpp
@@ -228,7 +228,7 @@ std::vector<irep_idt> java_class_loadert::load_entire_jar(
   return *classes;
 }
 
-optionalt<std::vector<irep_idt>> java_class_loadert::read_jar_file(
+std::optional<std::vector<irep_idt>> java_class_loadert::read_jar_file(
   const std::string &jar_path,
   message_handlert &message_handler)
 {
diff --git a/jbmc/src/java_bytecode/java_class_loader.h b/jbmc/src/java_bytecode/java_class_loader.h
index 1c7c7c14df6..163cc1df220 100644
--- a/jbmc/src/java_bytecode/java_class_loader.h
+++ b/jbmc/src/java_bytecode/java_class_loader.h
@@ -105,7 +105,7 @@ class java_class_loadert : public java_class_loader_baset
   /// Map from class names to the bytecode parse trees
   parse_tree_with_overridest_mapt class_map;
 
-  optionalt<std::vector<irep_idt>>
+  std::optional<std::vector<irep_idt>>
   read_jar_file(const std::string &jar_path, message_handlert &);
 };
 
diff --git a/jbmc/src/java_bytecode/java_class_loader_base.cpp b/jbmc/src/java_bytecode/java_class_loader_base.cpp
index 5a998bc4d63..49c56cf27fb 100644
--- a/jbmc/src/java_bytecode/java_class_loader_base.cpp
+++ b/jbmc/src/java_bytecode/java_class_loader_base.cpp
@@ -132,7 +132,7 @@ java_class_loader_baset::class_name_to_os_file(const irep_idt &class_name)
 }
 
 /// attempt to load a class from a classpath_entry
-optionalt<java_bytecode_parse_treet> java_class_loader_baset::load_class(
+std::optional<java_bytecode_parse_treet> java_class_loader_baset::load_class(
   const irep_idt &class_name,
   const classpath_entryt &cp_entry,
   message_handlert &message_handler)
@@ -154,7 +154,7 @@ optionalt<java_bytecode_parse_treet> java_class_loader_baset::load_class(
 /// \param jar_file: path of the jar file
 /// \param message_handler: message handler
 /// \return optional value of parse tree, empty if class cannot be loaded
-optionalt<java_bytecode_parse_treet>
+std::optional<java_bytecode_parse_treet>
 java_class_loader_baset::get_class_from_jar(
   const irep_idt &class_name,
   const std::string &jar_file,
@@ -189,7 +189,7 @@ java_class_loader_baset::get_class_from_jar(
 /// \param path: directory to load from
 /// \param message_handler: message handler
 /// \return optional value of parse tree, empty if class cannot be loaded
-optionalt<java_bytecode_parse_treet>
+std::optional<java_bytecode_parse_treet>
 java_class_loader_baset::get_class_from_directory(
   const irep_idt &class_name,
   const std::string &path,
diff --git a/jbmc/src/java_bytecode/java_class_loader_base.h b/jbmc/src/java_bytecode/java_class_loader_base.h
index 967b19d2bbc..5ae4874a6bc 100644
--- a/jbmc/src/java_bytecode/java_class_loader_base.h
+++ b/jbmc/src/java_bytecode/java_class_loader_base.h
@@ -10,7 +10,6 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_JAVA_BYTECODE_JAVA_CLASS_LOADER_BASE_H
 
 #include <util/irep.h>
-#include <util/optional.h>
 
 #include "jar_pool.h"
 
@@ -58,19 +57,19 @@ class java_class_loader_baset
   std::list<classpath_entryt> classpath_entries;
 
   /// attempt to load a class from a classpath_entry
-  optionalt<java_bytecode_parse_treet> load_class(
+  std::optional<java_bytecode_parse_treet> load_class(
     const irep_idt &class_name,
     const classpath_entryt &,
     message_handlert &);
 
   /// attempt to load a class from a given jar file
-  optionalt<java_bytecode_parse_treet> get_class_from_jar(
+  std::optional<java_bytecode_parse_treet> get_class_from_jar(
     const irep_idt &class_name,
     const std::string &jar_file,
     message_handlert &);
 
   /// attempt to load a class from a given directory
-  optionalt<java_bytecode_parse_treet> get_class_from_directory(
+  std::optional<java_bytecode_parse_treet> get_class_from_directory(
     const irep_idt &class_name,
     const std::string &path,
     message_handlert &);
diff --git a/jbmc/src/java_bytecode/java_entry_point.cpp b/jbmc/src/java_bytecode/java_entry_point.cpp
index 86c463480bc..fa074554c8e 100644
--- a/jbmc/src/java_bytecode/java_entry_point.cpp
+++ b/jbmc/src/java_bytecode/java_entry_point.cpp
@@ -32,7 +32,7 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #define JAVA_MAIN_METHOD "main:([Ljava/lang/String;)V"
 
-static optionalt<codet> record_return_value(
+static std::optional<codet> record_return_value(
   const symbolt &function,
   const symbol_table_baset &symbol_table);
 
@@ -493,7 +493,7 @@ static code_blockt java_record_outputs(
   return init_code;
 }
 
-static optionalt<codet> record_return_value(
+static std::optional<codet> record_return_value(
   const symbolt &function,
   const symbol_table_baset &symbol_table)
 {
diff --git a/jbmc/src/java_bytecode/java_object_factory.cpp b/jbmc/src/java_bytecode/java_object_factory.cpp
index 87faebded0e..b824caefcbc 100644
--- a/jbmc/src/java_bytecode/java_object_factory.cpp
+++ b/jbmc/src/java_bytecode/java_object_factory.cpp
@@ -100,7 +100,7 @@ class java_object_factoryt
     bool is_sub,
     bool skip_classid,
     lifetimet lifetime,
-    const optionalt<typet> &override_type,
+    const std::optional<typet> &override_type,
     size_t depth,
     update_in_placet,
     const source_locationt &location);
@@ -910,7 +910,7 @@ void java_object_factoryt::gen_nondet_struct_init(
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
   resolve_inherited_componentt resolve_inherited_component{symbol_table};
-  optionalt<resolve_inherited_componentt::inherited_componentt>
+  std::optional<resolve_inherited_componentt::inherited_componentt>
     cprover_nondet_initialize = resolve_inherited_component(
       "java::" + id2string(struct_tag), "cproverNondetInitialize:()V", true);
 
@@ -1002,7 +1002,7 @@ void java_object_factoryt::gen_nondet_init(
   bool is_sub,
   bool skip_classid,
   lifetimet lifetime,
-  const optionalt<typet> &override_type,
+  const std::optional<typet> &override_type,
   size_t depth,
   update_in_placet update_in_place,
   const source_locationt &location)
diff --git a/jbmc/src/java_bytecode/java_static_initializers.cpp b/jbmc/src/java_bytecode/java_static_initializers.cpp
index e107ea9e4d5..fad44b65958 100644
--- a/jbmc/src/java_bytecode/java_static_initializers.cpp
+++ b/jbmc/src/java_bytecode/java_static_initializers.cpp
@@ -782,7 +782,7 @@ class_to_declared_symbols(const symbol_table_baset &symbol_table)
   for(const auto &symbol_pair : symbol_table)
   {
     const symbolt &symbol = symbol_pair.second;
-    if(optionalt<irep_idt> declaring = declaring_class(symbol))
+    if(std::optional<irep_idt> declaring = declaring_class(symbol))
       result.emplace(*declaring, symbol);
   }
   return result;
@@ -792,7 +792,7 @@ code_blockt get_user_specified_clinit_body(
   const irep_idt &class_id,
   const json_objectt &static_values_json,
   symbol_table_baset &symbol_table,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
   size_t max_user_array_length,
   std::unordered_map<std::string, object_creation_referencet> &references,
   const std::unordered_multimap<irep_idt, symbolt>
diff --git a/jbmc/src/java_bytecode/java_static_initializers.h b/jbmc/src/java_bytecode/java_static_initializers.h
index 1f0dba5c955..3e2286bc3b9 100644
--- a/jbmc/src/java_bytecode/java_static_initializers.h
+++ b/jbmc/src/java_bytecode/java_static_initializers.h
@@ -86,7 +86,7 @@ code_blockt get_user_specified_clinit_body(
   const irep_idt &class_id,
   const json_objectt &static_values_json,
   symbol_table_baset &symbol_table,
-  optionalt<ci_lazy_methods_neededt> needed_lazy_methods,
+  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
   size_t max_user_array_length,
   std::unordered_map<std::string, object_creation_referencet> &references,
   const std::unordered_multimap<irep_idt, symbolt>
diff --git a/jbmc/src/java_bytecode/java_trace_validation.cpp b/jbmc/src/java_bytecode/java_trace_validation.cpp
index 519d57f5fa7..2680c4c1276 100644
--- a/jbmc/src/java_bytecode/java_trace_validation.cpp
+++ b/jbmc/src/java_bytecode/java_trace_validation.cpp
@@ -36,7 +36,7 @@ static bool may_be_lvalue(const exprt &expr)
          can_cast_expr<byte_extract_exprt>(expr);
 }
 
-optionalt<symbol_exprt> get_inner_symbol_expr(exprt expr)
+std::optional<symbol_exprt> get_inner_symbol_expr(exprt expr)
 {
   while(expr.has_operands())
   {
diff --git a/jbmc/src/java_bytecode/java_trace_validation.h b/jbmc/src/java_bytecode/java_trace_validation.h
index 7b0b5b8935b..0f4cef9450f 100644
--- a/jbmc/src/java_bytecode/java_trace_validation.h
+++ b/jbmc/src/java_bytecode/java_trace_validation.h
@@ -9,9 +9,10 @@ Author: Jeannie Moulton
 #ifndef CPROVER_JAVA_BYTECODE_JAVA_TRACE_VALIDATION_H
 #define CPROVER_JAVA_BYTECODE_JAVA_TRACE_VALIDATION_H
 
-#include <util/optional.h>
 #include <util/validation_mode.h>
 
+#include <optional>
+
 class goto_tracet;
 class namespacet;
 class exprt;
@@ -49,7 +50,7 @@ bool check_symbol_structure(const exprt &expr);
 
 /// Recursively extracts the first operand of an expression until it reaches a
 /// symbol and returns it, or returns an empty optional
-optionalt<symbol_exprt> get_inner_symbol_expr(exprt expr);
+std::optional<symbol_exprt> get_inner_symbol_expr(exprt expr);
 
 /// \return true iff the expression is a member expression (or nested member
 /// expression) of a valid symbol
diff --git a/jbmc/src/java_bytecode/java_types.cpp b/jbmc/src/java_bytecode/java_types.cpp
index 6793d6cb5ff..b5d7557a204 100644
--- a/jbmc/src/java_bytecode/java_types.cpp
+++ b/jbmc/src/java_bytecode/java_types.cpp
@@ -558,7 +558,7 @@ java_reference_typet java_reference_array_type(const struct_tag_typet &subtype)
 /// \param class_name_prefix: name of class to append to generic type
 ///   variables/parameters
 /// \return internal type representation for GOTO programs
-optionalt<typet> java_type_from_string(
+std::optional<typet> java_type_from_string(
   const std::string &src,
   const std::string &class_name_prefix)
 {
@@ -1072,7 +1072,7 @@ java_generic_struct_tag_typet::java_generic_struct_tag_typet(
 /// in the vector of generic types.
 /// \param type: The parameter type we are looking for.
 /// \return The index of the type in the vector of generic types.
-optionalt<size_t> java_generic_struct_tag_typet::generic_type_index(
+std::optional<size_t> java_generic_struct_tag_typet::generic_type_index(
   const java_generic_parametert &type) const
 {
   const auto &type_variable = type.get_name();
diff --git a/jbmc/src/java_bytecode/java_types.h b/jbmc/src/java_bytecode/java_types.h
index 5c38043c701..b1e2c1a4306 100644
--- a/jbmc/src/java_bytecode/java_types.h
+++ b/jbmc/src/java_bytecode/java_types.h
@@ -15,7 +15,6 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include <util/c_types.h>
 #include <util/narrow.h>
-#include <util/optional.h>
 #include <util/std_expr.h>
 
 class java_annotationt : public irept
@@ -672,7 +671,7 @@ exprt get_array_dimension_field(const exprt &pointer);
 exprt get_array_element_type_field(const exprt &pointer);
 
 typet java_type_from_char(char t);
-optionalt<typet> java_type_from_string(
+std::optional<typet> java_type_from_string(
   const std::string &,
   const std::string &class_name_prefix = "");
 char java_char_from_type(const typet &type);
@@ -880,7 +879,7 @@ class java_generic_struct_tag_typet : public struct_tag_typet
     return (generic_typest &)(add(ID_generic_types).get_sub());
   }
 
-  optionalt<size_t>
+  std::optional<size_t>
   generic_type_index(const java_generic_parametert &type) const;
 };
 
@@ -1138,9 +1137,9 @@ class unsupported_java_class_signature_exceptiont:public std::logic_error
   }
 };
 
-inline optionalt<typet> java_type_from_string_with_exception(
+inline std::optional<typet> java_type_from_string_with_exception(
   const std::string &descriptor,
-  const optionalt<std::string> &signature,
+  const std::optional<std::string> &signature,
   const std::string &class_name)
 {
   try
@@ -1157,7 +1156,7 @@ inline optionalt<typet> java_type_from_string_with_exception(
 /// \param gen_types: The subtypes array.
 /// \param identifier: The string identifier of the type of the component.
 /// \return Optional with the size if the identifier was found.
-inline const optionalt<size_t> java_generics_get_index_for_subtype(
+inline const std::optional<size_t> java_generics_get_index_for_subtype(
   const std::vector<java_generic_parametert> &gen_types,
   const irep_idt &identifier)
 {
diff --git a/jbmc/src/java_bytecode/java_utils.cpp b/jbmc/src/java_bytecode/java_utils.cpp
index 7f16b087364..dcd5cc86849 100644
--- a/jbmc/src/java_bytecode/java_utils.cpp
+++ b/jbmc/src/java_bytecode/java_utils.cpp
@@ -445,7 +445,7 @@ std::string pretty_print_java_type(const std::string &fqn_java_type)
 ///   ancestors including interfaces, rather than just parents.
 /// \return the concrete component referred to if any is found, or an invalid
 ///   resolve_inherited_componentt::inherited_componentt otherwise.
-optionalt<resolve_inherited_componentt::inherited_componentt>
+std::optional<resolve_inherited_componentt::inherited_componentt>
 get_inherited_component(
   const irep_idt &component_class_id,
   const irep_idt &component_name,
@@ -566,10 +566,10 @@ symbolt &fresh_java_symbol(
     type, name_prefix, basename_prefix, source_location, ID_java, symbol_table);
 }
 
-optionalt<irep_idt> declaring_class(const symbolt &symbol)
+std::optional<irep_idt> declaring_class(const symbolt &symbol)
 {
   const irep_idt &class_id = symbol.type.get(ID_C_class);
-  return class_id.empty() ? optionalt<irep_idt>{} : class_id;
+  return class_id.empty() ? std::optional<irep_idt>{} : class_id;
 }
 
 void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class)
@@ -577,7 +577,7 @@ void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class)
   symbol.type.set(ID_C_class, declaring_class);
 }
 
-[[nodiscard]] optionalt<std::string>
+[[nodiscard]] std::optional<std::string>
 class_name_from_method_name(const std::string &method_name)
 {
   const auto signature_index = method_name.rfind(":");
diff --git a/jbmc/src/java_bytecode/java_utils.h b/jbmc/src/java_bytecode/java_utils.h
index 1e23021188e..c07e2a716aa 100644
--- a/jbmc/src/java_bytecode/java_utils.h
+++ b/jbmc/src/java_bytecode/java_utils.h
@@ -153,7 +153,7 @@ irep_idt strip_java_namespace_prefix(const irep_idt &to_strip);
 
 std::string pretty_print_java_type(const std::string &fqn_java_type);
 
-optionalt<resolve_inherited_componentt::inherited_componentt>
+std::optional<resolve_inherited_componentt::inherited_componentt>
 get_inherited_component(
   const irep_idt &component_class_id,
   const irep_idt &component_name,
@@ -175,7 +175,7 @@ symbolt &fresh_java_symbol(
 /// symbol is not declared by a class then an empty optional is returned. This
 /// is used for method symbols and static field symbols to link them back to the
 /// class which declared them.
-optionalt<irep_idt> declaring_class(const symbolt &symbol);
+std::optional<irep_idt> declaring_class(const symbolt &symbol);
 
 /// Sets the identifier of the class which declared a given \p symbol to \p
 /// declaring_class.
@@ -184,7 +184,7 @@ void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class);
 /// Get JVM type name of the class in which \p method_name is defined.
 /// Returns an empty optional if the class name cannot be retrieved,
 /// e.g. method_name is an internal function.
-[[nodiscard]] optionalt<std::string>
+[[nodiscard]] std::optional<std::string>
 class_name_from_method_name(const std::string &method_name);
 
 #endif // CPROVER_JAVA_BYTECODE_JAVA_UTILS_H
diff --git a/jbmc/src/java_bytecode/lambda_synthesis.cpp b/jbmc/src/java_bytecode/lambda_synthesis.cpp
index 17975e12ff6..559acb80b04 100644
--- a/jbmc/src/java_bytecode/lambda_synthesis.cpp
+++ b/jbmc/src/java_bytecode/lambda_synthesis.cpp
@@ -51,7 +51,7 @@ irep_idt lambda_synthetic_class_name(
 ///   methods) of the class where the lambda is called
 /// \param index: Index of the lambda method handle in the vector
 /// \return Symbol of the lambda method if the method handle has a known type
-static optionalt<java_class_typet::java_lambda_method_handlet>
+static std::optional<java_class_typet::java_lambda_method_handlet>
 get_lambda_method_handle(
   const symbol_table_baset &symbol_table,
   const java_class_typet::java_lambda_method_handlest &lambda_method_handles,
@@ -73,7 +73,7 @@ get_lambda_method_handle(
   return {};
 }
 
-static optionalt<java_class_typet::java_lambda_method_handlet>
+static std::optional<java_class_typet::java_lambda_method_handlet>
 lambda_method_handle(
   const symbol_table_baset &symbol_table,
   const irep_idt &method_identifier,
@@ -605,7 +605,7 @@ static symbol_exprt instantiate_new_object(
 
 /// If \p maybe_boxed_type is a boxed primitive return its unboxing method;
 /// otherwise return empty.
-static optionalt<irep_idt>
+static std::optional<irep_idt>
 get_unboxing_method(const pointer_typet &maybe_boxed_type)
 {
   const irep_idt &boxed_type_id =
@@ -613,7 +613,7 @@ get_unboxing_method(const pointer_typet &maybe_boxed_type)
   const java_boxed_type_infot *boxed_type_info =
     get_boxed_type_info_by_name(boxed_type_id);
   return boxed_type_info ? boxed_type_info->unboxing_function_name
-                         : optionalt<irep_idt>{};
+                         : std::optional<irep_idt>{};
 }
 
 /// Produce a class_method_descriptor_exprt or symbol_exprt for
diff --git a/jbmc/src/java_bytecode/select_pointer_type.cpp b/jbmc/src/java_bytecode/select_pointer_type.cpp
index 154d3133d97..c6bceb4fd72 100644
--- a/jbmc/src/java_bytecode/select_pointer_type.cpp
+++ b/jbmc/src/java_bytecode/select_pointer_type.cpp
@@ -42,7 +42,7 @@ pointer_typet select_pointer_typet::specialize_generics(
       generic_parameter_specialization_map;
     while(true)
     {
-      const optionalt<reference_typet> specialization =
+      const std::optional<reference_typet> specialization =
         spec_map_copy.pop(parameter_name);
       if(!specialization)
       {
diff --git a/jbmc/src/jbmc/jbmc_parse_options.h b/jbmc/src/jbmc/jbmc_parse_options.h
index a7264b9dd5b..80a11dc1b52 100644
--- a/jbmc/src/jbmc/jbmc_parse_options.h
+++ b/jbmc/src/jbmc/jbmc_parse_options.h
@@ -135,7 +135,7 @@ class jbmc_parse_optionst : public parse_options_baset
   /// See java_bytecode_languaget::method_context.
   /// The two fields are initialized in exactly the same way.
   /// TODO Refactor this so it only needs to be computed once, in one place.
-  optionalt<prefix_filtert> method_context;
+  std::optional<prefix_filtert> method_context;
 };
 
 #endif // CPROVER_JBMC_JBMC_PARSE_OPTIONS_H
diff --git a/jbmc/src/jdiff/java_syntactic_diff.cpp b/jbmc/src/jdiff/java_syntactic_diff.cpp
index 8b4f6473b93..0a9d429a7d8 100644
--- a/jbmc/src/jdiff/java_syntactic_diff.cpp
+++ b/jbmc/src/jdiff/java_syntactic_diff.cpp
@@ -36,7 +36,7 @@ bool java_syntactic_difft::operator()()
     CHECK_RETURN(fun1 != nullptr);
     const symbolt *fun2 = goto_model2.symbol_table.lookup(gf_entry.first);
     CHECK_RETURN(fun2 != nullptr);
-    const optionalt<irep_idt> class_name = declaring_class(*fun1);
+    const std::optional<irep_idt> class_name = declaring_class(*fun1);
     bool function_access_changed =
       fun1->type.get(ID_access) != fun2->type.get(ID_access);
     bool class_access_changed = false;
diff --git a/jbmc/unit/java-testing-utils/require_goto_statements.cpp b/jbmc/unit/java-testing-utils/require_goto_statements.cpp
index fbae94a8d81..81248f7b8e8 100644
--- a/jbmc/unit/java-testing-utils/require_goto_statements.cpp
+++ b/jbmc/unit/java-testing-utils/require_goto_statements.cpp
@@ -71,7 +71,7 @@ require_goto_statements::pointer_assignment_locationt
 require_goto_statements::find_struct_component_assignments(
   const std::vector<codet> &statements,
   const irep_idt &structure_name,
-  const optionalt<irep_idt> &superclass_name,
+  const std::optional<irep_idt> &superclass_name,
   const irep_idt &component_name,
   const symbol_table_baset &symbol_table)
 {
@@ -383,10 +383,10 @@ get_ultimate_source_symbol(
 ///   `require_struct_component_assignment`.
 const irep_idt &require_goto_statements::require_struct_component_assignment(
   const irep_idt &structure_name,
-  const optionalt<irep_idt> &superclass_name,
+  const std::optional<irep_idt> &superclass_name,
   const irep_idt &component_name,
   const irep_idt &component_type_name,
-  const optionalt<irep_idt> &typecast_name,
+  const std::optional<irep_idt> &typecast_name,
   const std::vector<codet> &entry_point_instructions,
   const symbol_table_baset &symbol_table)
 {
@@ -445,7 +445,7 @@ const irep_idt &require_goto_statements::require_struct_component_assignment(
 const irep_idt &
 require_goto_statements::require_struct_array_component_assignment(
   const irep_idt &structure_name,
-  const optionalt<irep_idt> &superclass_name,
+  const std::optional<irep_idt> &superclass_name,
   const irep_idt &array_component_name,
   const irep_idt &array_type_name,
   const std::vector<codet> &entry_point_instructions,
diff --git a/jbmc/unit/java-testing-utils/require_goto_statements.h b/jbmc/unit/java-testing-utils/require_goto_statements.h
index 33f3dd744a7..ebd78d9d7e4 100644
--- a/jbmc/unit/java-testing-utils/require_goto_statements.h
+++ b/jbmc/unit/java-testing-utils/require_goto_statements.h
@@ -23,7 +23,7 @@ namespace require_goto_statements
 {
 struct pointer_assignment_locationt
 {
-  optionalt<code_assignt> null_assignment;
+  std::optional<code_assignt> null_assignment;
   std::vector<code_assignt> non_null_assignments;
 };
 
@@ -47,7 +47,7 @@ class no_decl_found_exceptiont : public std::exception
 pointer_assignment_locationt find_struct_component_assignments(
   const std::vector<codet> &statements,
   const irep_idt &structure_name,
-  const optionalt<irep_idt> &superclass_name,
+  const std::optional<irep_idt> &superclass_name,
   const irep_idt &component_name,
   const symbol_table_baset &symbol_table);
 
@@ -74,16 +74,16 @@ const code_declt &require_declaration_of_name(
 
 const irep_idt &require_struct_component_assignment(
   const irep_idt &structure_name,
-  const optionalt<irep_idt> &superclass_name,
+  const std::optional<irep_idt> &superclass_name,
   const irep_idt &component_name,
   const irep_idt &component_type_name,
-  const optionalt<irep_idt> &typecast_name,
+  const std::optional<irep_idt> &typecast_name,
   const std::vector<codet> &entry_point_instructions,
   const symbol_table_baset &symbol_table);
 
 const irep_idt &require_struct_array_component_assignment(
   const irep_idt &structure_name,
-  const optionalt<irep_idt> &superclass_name,
+  const std::optional<irep_idt> &superclass_name,
   const irep_idt &array_component_name,
   const irep_idt &array_type_name,
   const std::vector<codet> &entry_point_instructions,
diff --git a/jbmc/unit/java-testing-utils/require_type.cpp b/jbmc/unit/java-testing-utils/require_type.cpp
index c7648675765..4559d4348c5 100644
--- a/jbmc/unit/java-testing-utils/require_type.cpp
+++ b/jbmc/unit/java-testing-utils/require_type.cpp
@@ -17,7 +17,7 @@ Author: Diffblue Ltd.
 /// \return A cast to pointer_typet version of type
 pointer_typet require_type::require_pointer(
   const typet &type,
-  const optionalt<typet> &subtype)
+  const std::optional<typet> &subtype)
 {
   REQUIRE(type.id() == ID_pointer);
   const pointer_typet &pointer = to_pointer_type(type);
@@ -243,7 +243,7 @@ java_generic_parametert require_type::require_java_generic_parameter(
 /// \return The value passed in the first argument
 const typet &require_type::require_java_non_generic_type(
   const typet &type,
-  const optionalt<struct_tag_typet> &expect_subtype)
+  const std::optional<struct_tag_typet> &expect_subtype)
 {
   REQUIRE(!is_java_generic_parameter(type));
   REQUIRE(!is_java_generic_type(type));
diff --git a/jbmc/unit/java-testing-utils/require_type.h b/jbmc/unit/java-testing-utils/require_type.h
index d9e5135bc13..513593fb7cc 100644
--- a/jbmc/unit/java-testing-utils/require_type.h
+++ b/jbmc/unit/java-testing-utils/require_type.h
@@ -22,7 +22,7 @@ Author: Diffblue Ltd.
 namespace require_type
 {
 pointer_typet
-require_pointer(const typet &type, const optionalt<typet> &subtype);
+require_pointer(const typet &type, const std::optional<typet> &subtype);
 
 const struct_tag_typet &
 require_struct_tag(const typet &type, const irep_idt &identifier = "");
@@ -78,7 +78,7 @@ java_generic_parametert require_java_generic_parameter(
 
 const typet &require_java_non_generic_type(
   const typet &type,
-  const optionalt<struct_tag_typet> &expect_subtype);
+  const std::optional<struct_tag_typet> &expect_subtype);
 
 class_typet require_complete_class(const typet &class_type);
 
diff --git a/jbmc/unit/java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp b/jbmc/unit/java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp
index 41e422dea17..50710153209 100644
--- a/jbmc/unit/java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp
+++ b/jbmc/unit/java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp
@@ -28,7 +28,7 @@ SCENARIO(
     GIVEN(
       "A class with a static lambda variables from " + compiler + " compiler.")
     {
-      optionalt<java_bytecode_parse_treet> parse_tree = java_bytecode_parse(
+      std::optional<java_bytecode_parse_treet> parse_tree = java_bytecode_parse(
         "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
           compiler + "_classes/StaticLambdas.class",
         "StaticLambdas",
@@ -351,11 +351,12 @@ SCENARIO(
     [](const std::string &compiler) { // NOLINT(whitespace/braces)
       GIVEN("A method with local lambdas from " + compiler + " compiler.")
       {
-        optionalt<java_bytecode_parse_treet> parse_tree = java_bytecode_parse(
-          "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
-            compiler + "_classes/LocalLambdas.class",
-          "LocalLambdas",
-          null_message_handler);
+        std::optional<java_bytecode_parse_treet> parse_tree =
+          java_bytecode_parse(
+            "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
+              compiler + "_classes/LocalLambdas.class",
+            "LocalLambdas",
+            null_message_handler);
         WHEN("Parsing that class")
         {
           REQUIRE(parse_tree);
@@ -672,11 +673,12 @@ SCENARIO(
         "A class that has lambdas as member variables from " + compiler +
         " compiler.")
       {
-        optionalt<java_bytecode_parse_treet> parse_tree = java_bytecode_parse(
-          "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
-            compiler + "_classes/MemberLambdas.class",
-          "MemberLambdas",
-          null_message_handler);
+        std::optional<java_bytecode_parse_treet> parse_tree =
+          java_bytecode_parse(
+            "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
+              compiler + "_classes/MemberLambdas.class",
+            "MemberLambdas",
+            null_message_handler);
         WHEN("Parsing that class")
         {
           REQUIRE(parse_tree);
@@ -1019,11 +1021,12 @@ SCENARIO(
         "variables from " +
         compiler + " compiler.")
       {
-        optionalt<java_bytecode_parse_treet> parse_tree = java_bytecode_parse(
-          "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
-            compiler + "_classes/OuterMemberLambdas$Inner.class",
-          "OuterMemberLambdas$Inner",
-          null_message_handler);
+        std::optional<java_bytecode_parse_treet> parse_tree =
+          java_bytecode_parse(
+            "./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/" +
+              compiler + "_classes/OuterMemberLambdas$Inner.class",
+            "OuterMemberLambdas$Inner",
+            null_message_handler);
         WHEN("Parsing that class")
         {
           REQUIRE(parse_tree);
diff --git a/jbmc/unit/java_bytecode/java_static_initializers/assignments_from_json.cpp b/jbmc/unit/java_bytecode/java_static_initializers/assignments_from_json.cpp
index 55afffa9084..15598ef8e7b 100644
--- a/jbmc/unit/java_bytecode/java_static_initializers/assignments_from_json.cpp
+++ b/jbmc/unit/java_bytecode/java_static_initializers/assignments_from_json.cpp
@@ -91,7 +91,7 @@ SCENARIO(
 
     const reference_typet test_class_type =
       reference_type(struct_tag_typet{"java::TestClass"});
-    optionalt<ci_lazy_methods_neededt> option{};
+    std::optional<ci_lazy_methods_neededt> option{};
     const code_with_references_listt code = assign_from_json(
       symbol_exprt{"symbol_to_assign", test_class_type},
       json,
@@ -180,7 +180,7 @@ SCENARIO(
 
     const reference_typet test_class_type =
       reference_type(struct_tag_typet{"java::TestClass"});
-    optionalt<ci_lazy_methods_neededt> option{};
+    std::optional<ci_lazy_methods_neededt> option{};
     const code_with_references_listt code = assign_from_json(
       symbol_exprt{"symbol_to_assign", test_class_type},
       json,
@@ -303,7 +303,7 @@ SCENARIO(
 
     const reference_typet test_class_type =
       reference_type(struct_tag_typet{"java::TestClass"});
-    optionalt<ci_lazy_methods_neededt> option{};
+    std::optional<ci_lazy_methods_neededt> option{};
     const code_with_references_listt code = assign_from_json(
       symbol_exprt{"symbol_to_assign", test_class_type},
       json,
@@ -467,7 +467,7 @@ SCENARIO(
 
     const reference_typet test_class_type =
       reference_type(struct_tag_typet{"java::TestClass"});
-    optionalt<ci_lazy_methods_neededt> option{};
+    std::optional<ci_lazy_methods_neededt> option{};
     const code_with_references_listt code = assign_from_json(
       symbol_exprt{"symbol_to_assign", test_class_type},
       json,
diff --git a/jbmc/unit/solvers/strings/string_refinement/dependency_graph.cpp b/jbmc/unit/solvers/strings/string_refinement/dependency_graph.cpp
index 40b9ffef565..44464c46b2d 100644
--- a/jbmc/unit/solvers/strings/string_refinement/dependency_graph.cpp
+++ b/jbmc/unit/solvers/strings/string_refinement/dependency_graph.cpp
@@ -82,13 +82,13 @@ SCENARIO("dependency_graph", "[core][solvers][refinement][string_refinement]")
       symbol_generatort generator;
       array_poolt array_pool(generator);
 
-      optionalt<exprt> new_equation1 =
+      std::optional<exprt> new_equation1 =
         add_node(dependencies, equation1, array_pool, generator);
       REQUIRE(new_equation1.has_value());
-      optionalt<exprt> new_equation2 =
+      std::optional<exprt> new_equation2 =
         add_node(dependencies, equation2, array_pool, generator);
       REQUIRE(new_equation2.has_value());
-      optionalt<exprt> new_equation3 =
+      std::optional<exprt> new_equation3 =
         add_node(dependencies, equation3, array_pool, generator);
       REQUIRE(new_equation3.has_value());
 
diff --git a/src/analyses/call_graph.cpp b/src/analyses/call_graph.cpp
index 93278523c02..543e68302a4 100644
--- a/src/analyses/call_graph.cpp
+++ b/src/analyses/call_graph.cpp
@@ -296,12 +296,12 @@ void call_grapht::output_xml(std::ostream &out) const
   }
 }
 
-optionalt<std::size_t> call_grapht::directed_grapht::get_node_index(
-  const irep_idt &function) const
+std::optional<std::size_t>
+call_grapht::directed_grapht::get_node_index(const irep_idt &function) const
 {
   auto findit=nodes_by_name.find(function);
   if(findit==nodes_by_name.end())
-    return optionalt<node_indext>();
+    return std::optional<node_indext>();
   else
     return findit->second;
 }
diff --git a/src/analyses/call_graph.h b/src/analyses/call_graph.h
index 8abdbc13bf9..630f277f306 100644
--- a/src/analyses/call_graph.h
+++ b/src/analyses/call_graph.h
@@ -147,7 +147,7 @@ class call_grapht
     /// Find the graph node by function name
     /// \param function: function to find
     /// \return none if function is not in this graph, or some index otherwise.
-    optionalt<node_indext> get_node_index(const irep_idt &function) const;
+    std::optional<node_indext> get_node_index(const irep_idt &function) const;
 
     /// Type of the node name -> node index map.
     typedef std::unordered_map<irep_idt, node_indext> nodes_by_namet;
diff --git a/src/analyses/local_safe_pointers.cpp b/src/analyses/local_safe_pointers.cpp
index a7fe27f985f..a67816bce45 100644
--- a/src/analyses/local_safe_pointers.cpp
+++ b/src/analyses/local_safe_pointers.cpp
@@ -32,8 +32,8 @@ struct goto_null_checkt
 /// \param expr: expression to check
 /// \return a `goto_null_checkt` indicating what expression is tested and
 ///   whether the check applies on the taken or not-taken branch, or an empty
-///   optionalt if this isn't a null check.
-static optionalt<goto_null_checkt> get_null_checked_expr(const exprt &expr)
+///   std::optional if this isn't a null check.
+static std::optional<goto_null_checkt> get_null_checked_expr(const exprt &expr)
 {
   exprt normalized_expr = expr;
   // If true, then a null check is made when test `expr` passes; if false,
diff --git a/src/analyses/sese_regions.cpp b/src/analyses/sese_regions.cpp
index 727e0819ea3..240d5667845 100644
--- a/src/analyses/sese_regions.cpp
+++ b/src/analyses/sese_regions.cpp
@@ -146,7 +146,7 @@ void sese_region_analysist::compute_sese_regions(
     // but our current dominator analysis doesn't make it easy to determine an
     // immediate dominator.
 
-    // Ideally I would use `optionalt<std::size_t>` here, but it triggers a
+    // Ideally I would use `std::optional<std::size_t>` here, but it triggers a
     // GCC-5 bug.
     std::size_t closest_exit_index = dominators.cfg.size();
     for(const auto &possible_exit : instruction_postdoms)
diff --git a/src/analyses/sese_regions.h b/src/analyses/sese_regions.h
index 563bd0add05..52e882d1a67 100644
--- a/src/analyses/sese_regions.h
+++ b/src/analyses/sese_regions.h
@@ -12,13 +12,11 @@ Author: Diffblue Ltd.
 #ifndef CPROVER_ANALYSES_SESE_REGIONS_H
 #define CPROVER_ANALYSES_SESE_REGIONS_H
 
-#include <util/optional.h>
-
 class sese_region_analysist
 {
 public:
   void operator()(const goto_programt &goto_program);
-  optionalt<goto_programt::const_targett>
+  std::optional<goto_programt::const_targett>
   get_region_exit(goto_programt::const_targett entry) const
   {
     auto find_result = sese_regions.find(entry);
diff --git a/src/analyses/variable-sensitivity/interval_abstract_value.cpp b/src/analyses/variable-sensitivity/interval_abstract_value.cpp
index 5f3c6affb4f..51f738c5109 100644
--- a/src/analyses/variable-sensitivity/interval_abstract_value.cpp
+++ b/src/analyses/variable-sensitivity/interval_abstract_value.cpp
@@ -117,7 +117,8 @@ interval_from_x_ge_value(const exprt &value)
 static inline mp_integer force_value_from_expr(const exprt &value)
 {
   PRECONDITION(constant_interval_exprt::is_int(value.type()));
-  optionalt<mp_integer> maybe_integer_value = numeric_cast<mp_integer>(value);
+  std::optional<mp_integer> maybe_integer_value =
+    numeric_cast<mp_integer>(value);
   INVARIANT(maybe_integer_value.has_value(), "Input has to have a value");
   return maybe_integer_value.value();
 }
diff --git a/src/analyses/variable-sensitivity/liveness_context.h b/src/analyses/variable-sensitivity/liveness_context.h
index c15808cd98a..ff32786d648 100644
--- a/src/analyses/variable-sensitivity/liveness_context.h
+++ b/src/analyses/variable-sensitivity/liveness_context.h
@@ -83,7 +83,7 @@ class liveness_contextt : public write_location_contextt
   abstract_object_pointert
   reset_location_on_merge(const liveness_context_ptrt &merged) const;
 
-  optionalt<locationt> assign_location;
+  std::optional<locationt> assign_location;
 
   context_abstract_object_ptrt
   update_location_context_internal(const locationst &locations) const override;
diff --git a/src/ansi-c/c_expr.cpp b/src/ansi-c/c_expr.cpp
index 92cec4044f2..a763f0fb550 100644
--- a/src/ansi-c/c_expr.cpp
+++ b/src/ansi-c/c_expr.cpp
@@ -15,7 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com
 
 shuffle_vector_exprt::shuffle_vector_exprt(
   exprt vector1,
-  optionalt<exprt> vector2,
+  std::optional<exprt> vector2,
   exprt::operandst indices)
   : multi_ary_exprt(
       ID_shuffle_vector,
diff --git a/src/ansi-c/c_expr.h b/src/ansi-c/c_expr.h
index 55b820cc60f..13a7ceca4eb 100644
--- a/src/ansi-c/c_expr.h
+++ b/src/ansi-c/c_expr.h
@@ -21,7 +21,7 @@ class shuffle_vector_exprt : public multi_ary_exprt
 public:
   shuffle_vector_exprt(
     exprt vector1,
-    optionalt<exprt> vector2,
+    std::optional<exprt> vector2,
     exprt::operandst indices);
 
   const vector_typet &type() const
diff --git a/src/ansi-c/c_typecast.cpp b/src/ansi-c/c_typecast.cpp
index fe7ea79939d..10547403f5a 100644
--- a/src/ansi-c/c_typecast.cpp
+++ b/src/ansi-c/c_typecast.cpp
@@ -775,7 +775,7 @@ void c_typecastt::do_typecast(exprt &expr, const typet &dest_type)
   }
 }
 
-optionalt<std::string>
+std::optional<std::string>
 c_typecastt::check_address_can_be_taken(const typet &type)
 {
   if(type.id() == ID_c_bit_field)
diff --git a/src/ansi-c/c_typecast.h b/src/ansi-c/c_typecast.h
index 3416677a515..9585d99b7cb 100644
--- a/src/ansi-c/c_typecast.h
+++ b/src/ansi-c/c_typecast.h
@@ -10,9 +10,8 @@ Author: Daniel Kroening, kroening@kroening.com
 #ifndef CPROVER_ANSI_C_C_TYPECAST_H
 #define CPROVER_ANSI_C_C_TYPECAST_H
 
-#include <util/optional.h>
-
 #include <list>
+#include <optional>
 #include <string>
 
 class exprt;
@@ -69,7 +68,7 @@ class c_typecastt
 
   /// \return empty when address can be taken,
   /// error message otherwise
-  static optionalt<std::string> check_address_can_be_taken(const typet &);
+  static std::optional<std::string> check_address_can_be_taken(const typet &);
 
 protected:
   const namespacet &ns;
diff --git a/src/ansi-c/c_typecheck_base.h b/src/ansi-c/c_typecheck_base.h
index d413f0dcf8c..bbe4948376e 100644
--- a/src/ansi-c/c_typecheck_base.h
+++ b/src/ansi-c/c_typecheck_base.h
@@ -228,14 +228,14 @@ class c_typecheck_baset:
     const irep_idt &arith_op);
   exprt
   typecheck_saturating_arithmetic(const side_effect_expr_function_callt &expr);
-  virtual optionalt<symbol_exprt> typecheck_gcc_polymorphic_builtin(
+  virtual std::optional<symbol_exprt> typecheck_gcc_polymorphic_builtin(
     const irep_idt &identifier,
     const exprt::operandst &arguments,
     const source_locationt &source_location);
   virtual code_blockt instantiate_gcc_polymorphic_builtin(
     const irep_idt &identifier,
     const symbol_exprt &function_symbol);
-  virtual optionalt<symbol_exprt>
+  virtual std::optional<symbol_exprt>
   typecheck_shadow_memory_builtin(const side_effect_expr_function_callt &expr);
   virtual exprt
   typecheck_shuffle_vector(const side_effect_expr_function_callt &expr);
diff --git a/src/ansi-c/c_typecheck_gcc_polymorphic_builtins.cpp b/src/ansi-c/c_typecheck_gcc_polymorphic_builtins.cpp
index 40bb18332f6..162daad11d8 100644
--- a/src/ansi-c/c_typecheck_gcc_polymorphic_builtins.cpp
+++ b/src/ansi-c/c_typecheck_gcc_polymorphic_builtins.cpp
@@ -490,7 +490,8 @@ static symbol_exprt typecheck_atomic_fetch_op(
   return result;
 }
 
-optionalt<symbol_exprt> c_typecheck_baset::typecheck_gcc_polymorphic_builtin(
+std::optional<symbol_exprt>
+c_typecheck_baset::typecheck_gcc_polymorphic_builtin(
   const irep_idt &identifier,
   const exprt::operandst &arguments,
   const source_locationt &source_location)
@@ -1420,7 +1421,7 @@ exprt c_typecheck_baset::typecheck_shuffle_vector(
     const exprt &arg0 = arguments[0];
     const vector_typet &input_vec_type = to_vector_type(arg0.type());
 
-    optionalt<exprt> arg1;
+    std::optional<exprt> arg1;
     if(arguments.size() == 3)
     {
       if(arguments[1].type() != input_vec_type)
diff --git a/src/ansi-c/c_typecheck_shadow_memory_builtin.cpp b/src/ansi-c/c_typecheck_shadow_memory_builtin.cpp
index 4e1915a6873..26667aca9df 100644
--- a/src/ansi-c/c_typecheck_shadow_memory_builtin.cpp
+++ b/src/ansi-c/c_typecheck_shadow_memory_builtin.cpp
@@ -223,7 +223,7 @@ static symbol_exprt typecheck_set_field(
 
 /// Typecheck the function if it is a shadow_memory builtin and return a symbol
 /// for it. Otherwise return empty.
-optionalt<symbol_exprt> c_typecheck_baset::typecheck_shadow_memory_builtin(
+std::optional<symbol_exprt> c_typecheck_baset::typecheck_shadow_memory_builtin(
   const side_effect_expr_function_callt &expr)
 {
   const exprt &f_op = expr.function();
diff --git a/src/ansi-c/expr2c.cpp b/src/ansi-c/expr2c.cpp
index dcf84fcfdde..1175ed6b04b 100644
--- a/src/ansi-c/expr2c.cpp
+++ b/src/ansi-c/expr2c.cpp
@@ -1719,7 +1719,7 @@ std::string expr2ct::convert_object_descriptor(
   return result;
 }
 
-static optionalt<exprt>
+static std::optional<exprt>
 build_sizeof_expr(const constant_exprt &expr, const namespacet &ns)
 {
   const typet &type = static_cast<const typet &>(expr.find(ID_C_c_sizeof_type));
@@ -1728,7 +1728,7 @@ build_sizeof_expr(const constant_exprt &expr, const namespacet &ns)
     return {};
 
   const auto type_size_expr = size_of_expr(type, ns);
-  optionalt<mp_integer> type_size;
+  std::optional<mp_integer> type_size;
   if(type_size_expr.has_value())
     type_size = numeric_cast<mp_integer>(*type_size_expr);
   auto val = numeric_cast<mp_integer>(expr);
@@ -4066,7 +4066,7 @@ std::string expr2ct::convert_with_precedence(
   return convert_norep(src, precedence);
 }
 
-optionalt<std::string> expr2ct::convert_function(const exprt &src)
+std::optional<std::string> expr2ct::convert_function(const exprt &src)
 {
   static const std::map<irep_idt, std::string> function_names = {
     {"buffer_size", "BUFFER_SIZE"},
diff --git a/src/ansi-c/expr2c_class.h b/src/ansi-c/expr2c_class.h
index 07d73975a3f..6ede63b7c2b 100644
--- a/src/ansi-c/expr2c_class.h
+++ b/src/ansi-c/expr2c_class.h
@@ -185,7 +185,7 @@ class expr2ct
 
   /// Returns a string if \p src is a function with a known conversion, else
   /// returns nullopt.
-  optionalt<std::string> convert_function(const exprt &src);
+  std::optional<std::string> convert_function(const exprt &src);
   std::string convert_function(const exprt &src, const std::string &symbol);
 
   std::string convert_complex(
diff --git a/src/ansi-c/goto_check_c.cpp b/src/ansi-c/goto_check_c.cpp
index 59915865a0b..a05a9953b17 100644
--- a/src/ansi-c/goto_check_c.cpp
+++ b/src/ansi-c/goto_check_c.cpp
@@ -213,7 +213,7 @@ class goto_check_ct
   ///   checking
   bool requires_pointer_primitive_check(const exprt &expr);
 
-  optionalt<goto_check_ct::conditiont>
+  std::optional<goto_check_ct::conditiont>
   get_pointer_is_null_condition(const exprt &address, const exprt &size);
   conditionst get_pointer_points_to_valid_memory_conditions(
     const exprt &address,
@@ -322,7 +322,7 @@ class goto_check_ct
   } check_statust;
 
   /// optional (named-check, status) pair
-  using named_check_statust = optionalt<std::pair<irep_idt, check_statust>>;
+  using named_check_statust = std::optional<std::pair<irep_idt, check_statust>>;
 
   /// Matches a named-check string of the form
   ///
@@ -2343,7 +2343,7 @@ goto_check_ct::get_pointer_points_to_valid_memory_conditions(
   return conditions;
 }
 
-optionalt<goto_check_ct::conditiont>
+std::optional<goto_check_ct::conditiont>
 goto_check_ct::get_pointer_is_null_condition(
   const exprt &address,
   const exprt &size)
diff --git a/src/ansi-c/padding.cpp b/src/ansi-c/padding.cpp
index a7b4f21d4e0..d7996e6d831 100644
--- a/src/ansi-c/padding.cpp
+++ b/src/ansi-c/padding.cpp
@@ -101,7 +101,7 @@ mp_integer alignment(const typet &type, const namespacet &ns)
   return result;
 }
 
-static optionalt<std::size_t>
+static std::optional<std::size_t>
 underlying_width(const c_bit_field_typet &type, const namespacet &ns)
 {
   const typet &underlying_type = type.underlying_type();
diff --git a/src/cpp/cpp_constructor.cpp b/src/cpp/cpp_constructor.cpp
index 09e022073cd..205ec052dd8 100644
--- a/src/cpp/cpp_constructor.cpp
+++ b/src/cpp/cpp_constructor.cpp
@@ -19,7 +19,7 @@ Author: Daniel Kroening, kroening@cs.cmu.edu
 /// \param object: non-typechecked object
 /// \param operands: non-typechecked operands
 /// \return typechecked code
-optionalt<codet> cpp_typecheckt::cpp_constructor(
+std::optional<codet> cpp_typecheckt::cpp_constructor(
   const source_locationt &source_location,
   const exprt &object,
   const exprt::operandst &operands)
diff --git a/src/cpp/cpp_destructor.cpp b/src/cpp/cpp_destructor.cpp
index d7f895f8bd1..5f2ee3dbe16 100644
--- a/src/cpp/cpp_destructor.cpp
+++ b/src/cpp/cpp_destructor.cpp
@@ -16,7 +16,7 @@ Author: Daniel Kroening, kroening@cs.cmu.edu
 #include <util/c_types.h>
 
 /// \return typechecked code
-optionalt<codet> cpp_typecheckt::cpp_destructor(
+std::optional<codet> cpp_typecheckt::cpp_destructor(
   const source_locationt &source_location,
   const exprt &object)
 {
diff --git a/src/cpp/cpp_typecheck.h b/src/cpp/cpp_typecheck.h
index 7c625f4ba6d..814b3d8c13e 100644
--- a/src/cpp/cpp_typecheck.h
+++ b/src/cpp/cpp_typecheck.h
@@ -98,7 +98,7 @@ class cpp_typecheckt:public c_typecheck_baset
 
   bool cpp_is_pod(const typet &type) const;
 
-  optionalt<codet> cpp_constructor(
+  std::optional<codet> cpp_constructor(
     const source_locationt &source_location,
     const exprt &object,
     const exprt::operandst &operands);
@@ -430,7 +430,7 @@ class cpp_typecheckt:public c_typecheck_baset
 
   const struct_typet &this_struct_type();
 
-  optionalt<codet>
+  std::optional<codet>
   cpp_destructor(const source_locationt &source_location, const exprt &object);
 
   // expressions
diff --git a/src/cpp/parse.cpp b/src/cpp/parse.cpp
index 4e866b9fdd1..c16a92a6d12 100644
--- a/src/cpp/parse.cpp
+++ b/src/cpp/parse.cpp
@@ -231,7 +231,7 @@ class Parser // NOLINT(readability/identifiers)
   bool rNullDeclaration(cpp_declarationt &);
   bool rTypedef(cpp_declarationt &);
   bool rTypedefUsing(cpp_declarationt &);
-  optionalt<codet> rTypedefStatement();
+  std::optional<codet> rTypedefStatement();
   bool rTypeSpecifier(typet &, bool);
   bool isTypeSpecifier();
   bool rLinkageSpec(cpp_linkage_spect &);
@@ -341,20 +341,20 @@ class Parser // NOLINT(readability/identifiers)
   bool maybeTemplateArgs();
 
   bool rFunctionBody(cpp_declaratort &);
-  optionalt<codet> rCompoundStatement();
-  optionalt<codet> rStatement();
-  optionalt<codet> rIfStatement();
-  optionalt<codet> rSwitchStatement();
-  optionalt<codet> rWhileStatement();
-  optionalt<codet> rDoStatement();
-  optionalt<codet> rForStatement();
-  optionalt<codet> rTryStatement();
-
-  optionalt<codet> rExprStatement();
-  optionalt<codet> rDeclarationStatement();
-  optionalt<codet>
+  std::optional<codet> rCompoundStatement();
+  std::optional<codet> rStatement();
+  std::optional<codet> rIfStatement();
+  std::optional<codet> rSwitchStatement();
+  std::optional<codet> rWhileStatement();
+  std::optional<codet> rDoStatement();
+  std::optional<codet> rForStatement();
+  std::optional<codet> rTryStatement();
+
+  std::optional<codet> rExprStatement();
+  std::optional<codet> rDeclarationStatement();
+  std::optional<codet>
   rIntegralDeclStatement(cpp_storage_spect &, typet &, typet &);
-  optionalt<codet> rOtherDeclStatement(cpp_storage_spect &, typet &);
+  std::optional<codet> rOtherDeclStatement(cpp_storage_spect &, typet &);
 
   bool MaybeTypeNameOrClassTemplate(cpp_tokent &);
   void SkipTo(int token);
@@ -363,13 +363,13 @@ class Parser // NOLINT(readability/identifiers)
   bool rString(cpp_tokent &tk);
 
   // GCC extensions
-  optionalt<codet> rGCCAsmStatement();
+  std::optional<codet> rGCCAsmStatement();
 
   // MSC extensions
-  optionalt<codet> rMSC_tryStatement();
-  optionalt<codet> rMSC_leaveStatement();
-  optionalt<codet> rMSCAsmStatement();
-  optionalt<codet> rMSC_if_existsStatement();
+  std::optional<codet> rMSC_tryStatement();
+  std::optional<codet> rMSC_leaveStatement();
+  std::optional<codet> rMSCAsmStatement();
+  std::optional<codet> rMSC_if_existsStatement();
   bool rTypePredicate(exprt &);
   bool rMSCuuidof(exprt &);
   bool rMSC_if_existsExpr(exprt &);
@@ -680,7 +680,7 @@ bool Parser::rTypedefUsing(cpp_declarationt &declaration)
   return true;
 }
 
-optionalt<codet> Parser::rTypedefStatement()
+std::optional<codet> Parser::rTypedefStatement()
 {
   cpp_declarationt declaration;
   if(!rTypedef(declaration))
@@ -6573,7 +6573,7 @@ bool Parser::rMSC_if_existsExpr(exprt &expr)
   return true;
 }
 
-optionalt<codet> Parser::rMSC_if_existsStatement()
+std::optional<codet> Parser::rMSC_if_existsStatement()
 {
   cpp_tokent tk1;
 
@@ -7235,7 +7235,7 @@ bool Parser::rFunctionBody(cpp_declaratort &declarator)
   compound.statement
   : '{' (statement)* '}'
 */
-optionalt<codet> Parser::rCompoundStatement()
+std::optional<codet> Parser::rCompoundStatement()
 {
   cpp_tokent ob, cb;
 
@@ -7296,7 +7296,7 @@ optionalt<codet> Parser::rCompoundStatement()
   | USING { NAMESPACE } identifier ';'
   | STATIC_ASSERT ( expression ',' expression ) ';'
 */
-optionalt<codet> Parser::rStatement()
+std::optional<codet> Parser::rStatement()
 {
   cpp_tokent tk1, tk2, tk3;
   int k;
@@ -7548,7 +7548,7 @@ optionalt<codet> Parser::rStatement()
   if.statement
   : IF '(' comma.expression ')' statement { ELSE statement }
 */
-optionalt<codet> Parser::rIfStatement()
+std::optional<codet> Parser::rIfStatement()
 {
   cpp_tokent tk1, tk2, tk3, tk4;
 
@@ -7595,7 +7595,7 @@ optionalt<codet> Parser::rIfStatement()
   switch.statement
   : SWITCH '(' comma.expression ')' statement
 */
-optionalt<codet> Parser::rSwitchStatement()
+std::optional<codet> Parser::rSwitchStatement()
 {
   cpp_tokent tk1, tk2, tk3;
 
@@ -7626,7 +7626,7 @@ optionalt<codet> Parser::rSwitchStatement()
   while.statement
   : WHILE '(' comma.expression ')' statement
 */
-optionalt<codet> Parser::rWhileStatement()
+std::optional<codet> Parser::rWhileStatement()
 {
   cpp_tokent tk1, tk2, tk3;
 
@@ -7657,7 +7657,7 @@ optionalt<codet> Parser::rWhileStatement()
   do.statement
   : DO statement WHILE '(' comma.expression ')' ';'
 */
-optionalt<codet> Parser::rDoStatement()
+std::optional<codet> Parser::rDoStatement()
 {
   cpp_tokent tk0, tk1, tk2, tk3, tk4;
 
@@ -7694,7 +7694,7 @@ optionalt<codet> Parser::rDoStatement()
   : FOR '(' expr.statement {comma.expression} ';' {comma.expression} ')'
     statement
 */
-optionalt<codet> Parser::rForStatement()
+std::optional<codet> Parser::rForStatement()
 {
   cpp_tokent tk1, tk2, tk3, tk4;
 
@@ -7751,7 +7751,7 @@ optionalt<codet> Parser::rForStatement()
   exception.handler
   : CATCH '(' (arg.declaration | Ellipsis) ')' compound.statement
 */
-optionalt<codet> Parser::rTryStatement()
+std::optional<codet> Parser::rTryStatement()
 {
   cpp_tokent try_token;
 
@@ -7777,7 +7777,7 @@ optionalt<codet> Parser::rTryStatement()
     if(lex.get_token(op_token)!='(')
       return {};
 
-    optionalt<codet> catch_op;
+    std::optional<codet> catch_op;
 
     if(lex.LookAhead(0)==TOK_ELLIPSIS)
     {
@@ -7827,7 +7827,7 @@ optionalt<codet> Parser::rTryStatement()
   return std::move(statement);
 }
 
-optionalt<codet> Parser::rMSC_tryStatement()
+std::optional<codet> Parser::rMSC_tryStatement()
 {
   // These are for 'structured exception handling',
   // and are a relic from Visual C.
@@ -7889,7 +7889,7 @@ optionalt<codet> Parser::rMSC_tryStatement()
     return {};
 }
 
-optionalt<codet> Parser::rMSC_leaveStatement()
+std::optional<codet> Parser::rMSC_leaveStatement()
 {
   // These are for 'structured exception handling',
   // and are a relic from Visual C.
@@ -7905,7 +7905,7 @@ optionalt<codet> Parser::rMSC_leaveStatement()
   return std::move(statement);
 }
 
-optionalt<codet> Parser::rGCCAsmStatement()
+std::optional<codet> Parser::rGCCAsmStatement()
 {
   cpp_tokent tk;
 
@@ -8004,7 +8004,7 @@ optionalt<codet> Parser::rGCCAsmStatement()
   return std::move(statement);
 }
 
-optionalt<codet> Parser::rMSCAsmStatement()
+std::optional<codet> Parser::rMSCAsmStatement()
 {
   cpp_tokent tk;
 
@@ -8080,7 +8080,7 @@ optionalt<codet> Parser::rMSCAsmStatement()
   | openc++.postfix.expr
   | openc++.primary.exp
 */
-optionalt<codet> Parser::rExprStatement()
+std::optional<codet> Parser::rExprStatement()
 {
   cpp_tokent tk;
 
@@ -8191,7 +8191,7 @@ bool Parser::rCondition(exprt &statement)
 
   Note: if you modify this function, take a look at rDeclaration(), too.
 */
-optionalt<codet> Parser::rDeclarationStatement()
+std::optional<codet> Parser::rDeclarationStatement()
 {
   cpp_storage_spect storage_spec;
   typet cv_q, integral;
@@ -8261,7 +8261,7 @@ optionalt<codet> Parser::rDeclarationStatement()
   integral.decl.statement
   : decl.head integral.or.class.spec {cv.qualify} {declarators} ';'
 */
-optionalt<codet> Parser::rIntegralDeclStatement(
+std::optional<codet> Parser::rIntegralDeclStatement(
   cpp_storage_spect &storage_spec,
   typet &integral,
   typet &cv_q)
@@ -8304,7 +8304,7 @@ optionalt<codet> Parser::rIntegralDeclStatement(
    other.decl.statement
    :decl.head name {cv.qualify} declarators ';'
 */
-optionalt<codet>
+std::optional<codet>
 Parser::rOtherDeclStatement(cpp_storage_spect &storage_spec, typet &cv_q)
 {
   typet type_name;
diff --git a/src/cprover/bv_pointers_wide.cpp b/src/cprover/bv_pointers_wide.cpp
index 1fe3acf7d44..6dc8a74b749 100644
--- a/src/cprover/bv_pointers_wide.cpp
+++ b/src/cprover/bv_pointers_wide.cpp
@@ -161,7 +161,7 @@ bv_pointers_widet::bv_pointers_widet(
 {
 }
 
-optionalt<bvt> bv_pointers_widet::convert_address_of_rec(const exprt &expr)
+std::optional<bvt> bv_pointers_widet::convert_address_of_rec(const exprt &expr)
 {
   if(expr.id() == ID_symbol)
   {
diff --git a/src/cprover/bv_pointers_wide.h b/src/cprover/bv_pointers_wide.h
index 02f65e13897..1c1f0be60fb 100644
--- a/src/cprover/bv_pointers_wide.h
+++ b/src/cprover/bv_pointers_wide.h
@@ -64,7 +64,7 @@ class bv_pointers_widet : public boolbvt
   exprt
   bv_get_rec(const exprt &, const bvt &, std::size_t offset) const override;
 
-  [[nodiscard]] optionalt<bvt> convert_address_of_rec(const exprt &);
+  [[nodiscard]] std::optional<bvt> convert_address_of_rec(const exprt &);
 
   [[nodiscard]] bvt
   offset_arithmetic(const pointer_typet &, const bvt &, const mp_integer &);
diff --git a/src/cprover/counterexample_found.cpp b/src/cprover/counterexample_found.cpp
index ff488f82f6a..40142d6a28b 100644
--- a/src/cprover/counterexample_found.cpp
+++ b/src/cprover/counterexample_found.cpp
@@ -170,7 +170,7 @@ propertyt::tracet counterexample(
   return trace;
 }
 
-optionalt<propertyt::tracet> counterexample_found(
+std::optional<propertyt::tracet> counterexample_found(
   const std::vector<framet> &frames,
   const workt &work,
   const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
diff --git a/src/cprover/counterexample_found.h b/src/cprover/counterexample_found.h
index bd848f0ad2a..5a7fe9e2d37 100644
--- a/src/cprover/counterexample_found.h
+++ b/src/cprover/counterexample_found.h
@@ -16,7 +16,7 @@ Author: Daniel Kroening, dkr@amazon.com
 
 #include <unordered_set>
 
-optionalt<propertyt::tracet> counterexample_found(
+std::optional<propertyt::tracet> counterexample_found(
   const std::vector<framet> &,
   const workt &,
   const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
diff --git a/src/cprover/cprover_parse_options.cpp b/src/cprover/cprover_parse_options.cpp
index 977ac1186c7..1bd9203bdb8 100644
--- a/src/cprover/cprover_parse_options.cpp
+++ b/src/cprover/cprover_parse_options.cpp
@@ -215,10 +215,10 @@ int cprover_parse_optionst::main()
       return CPROVER_EXIT_SUCCESS;
     }
 
-    // gcc produces a spurious warning for optionalt<irep_idt> if initialised
-    // with ternary operator. Initialising with an immediately invoked lamda
-    // avoids this.
-    const auto contract = [&]() -> optionalt<irep_idt> {
+    // gcc produces a spurious warning for std::optional<irep_idt> if
+    // initialised with ternary operator. Initialising with an immediately
+    // invoked lambda avoids this.
+    const auto contract = [&]() -> std::optional<irep_idt> {
       if(cmdline.isset("contract"))
         return {cmdline.get_value("contract")};
       else
diff --git a/src/cprover/inductiveness.h b/src/cprover/inductiveness.h
index 3368d9fbbf7..369966e2796 100644
--- a/src/cprover/inductiveness.h
+++ b/src/cprover/inductiveness.h
@@ -45,7 +45,7 @@ class inductiveness_resultt
     return result;
   }
 
-  optionalt<workt> work;
+  std::optional<workt> work;
 
 private:
   explicit inductiveness_resultt(outcomet __outcome) : outcome(__outcome)
diff --git a/src/cprover/instrument_contracts.cpp b/src/cprover/instrument_contracts.cpp
index ff6e71a6834..b68b49681dd 100644
--- a/src/cprover/instrument_contracts.cpp
+++ b/src/cprover/instrument_contracts.cpp
@@ -24,7 +24,7 @@ Author: Daniel Kroening, dkr@amazon.com
 
 #define MAX_TEXT 20
 
-optionalt<code_with_contract_typet>
+std::optional<code_with_contract_typet>
 get_contract(const irep_idt &function_identifier, const namespacet &ns)
 {
   // contracts are in a separate symbol, with prefix "contract::"
@@ -343,7 +343,7 @@ void instrument_contract_checks(
   {
     for(auto &instruction : body.instructions)
       instruction.transform(
-        [&old_prefix, &old_exprs](exprt expr) -> optionalt<exprt> {
+        [&old_prefix, &old_exprs](exprt expr) -> std::optional<exprt> {
           return replace_old(expr, old_prefix, old_exprs);
         });
   }
diff --git a/src/cprover/instrument_contracts.h b/src/cprover/instrument_contracts.h
index f33f17c1c02..04f269a9970 100644
--- a/src/cprover/instrument_contracts.h
+++ b/src/cprover/instrument_contracts.h
@@ -13,7 +13,8 @@ Author: Daniel Kroening, dkr@amazon.com
 #define CPROVER_CPROVER_INSTRUMENT_CONTRACTS_H
 
 #include <util/irep.h>
-#include <util/optional.h>
+
+#include <optional>
 
 class code_with_contract_typet;
 class goto_modelt;
@@ -21,7 +22,7 @@ class namespacet;
 
 void instrument_contracts(goto_modelt &);
 
-optionalt<code_with_contract_typet>
+std::optional<code_with_contract_typet>
 get_contract(const irep_idt &function_identifier, const namespacet &);
 
 #endif // CPROVER_CPOVER_INSTRUMENT_CONTRACTS_H
diff --git a/src/cprover/may_alias.cpp b/src/cprover/may_alias.cpp
index 2dd005535f8..b3cc69fb84d 100644
--- a/src/cprover/may_alias.cpp
+++ b/src/cprover/may_alias.cpp
@@ -92,7 +92,7 @@ bool prefix_of(const typet &a, const typet &b, const namespacet &ns)
   return a_struct.is_prefix_of(b_struct) || b_struct.is_prefix_of(a_struct);
 }
 
-static optionalt<object_address_exprt> find_object(const exprt &expr)
+static std::optional<object_address_exprt> find_object(const exprt &expr)
 {
   if(expr.id() == ID_object_address)
     return to_object_address_expr(expr);
@@ -145,7 +145,7 @@ static exprt drop_pointer_typecasts(exprt src)
     return src;
 }
 
-optionalt<exprt>
+std::optional<exprt>
 same_address(const exprt &a, const exprt &b, const namespacet &ns)
 {
   static const auto true_expr = true_exprt();
@@ -219,7 +219,7 @@ same_address(const exprt &a, const exprt &b, const namespacet &ns)
   return {};
 }
 
-optionalt<exprt> may_alias(
+std::optional<exprt> may_alias(
   const exprt &a,
   const exprt &b,
   const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
diff --git a/src/cprover/may_alias.h b/src/cprover/may_alias.h
index feeee1c89c0..11e8b29c4ac 100644
--- a/src/cprover/may_alias.h
+++ b/src/cprover/may_alias.h
@@ -21,7 +21,7 @@ class namespacet;
 bool is_object_field_element(const exprt &);
 
 // check whether the given two addresses may be aliases
-optionalt<exprt> may_alias(
+std::optional<exprt> may_alias(
   const exprt &,
   const exprt &,
   const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
diff --git a/src/cprover/report_traces.cpp b/src/cprover/report_traces.cpp
index 9a96fd648dc..09833323dbe 100644
--- a/src/cprover/report_traces.cpp
+++ b/src/cprover/report_traces.cpp
@@ -17,7 +17,7 @@ Author: Daniel Kroening, dkr@amazon.com
 
 #include <iomanip>
 
-optionalt<exprt> address_to_lvalue(exprt src)
+std::optional<exprt> address_to_lvalue(exprt src)
 {
   if(src.id() == ID_object_address)
     return to_object_address_expr(src).object_expr();
diff --git a/src/cprover/sentinel_dll.cpp b/src/cprover/sentinel_dll.cpp
index 071e811bb0e..1ae2eea45b2 100644
--- a/src/cprover/sentinel_dll.cpp
+++ b/src/cprover/sentinel_dll.cpp
@@ -17,7 +17,7 @@ Author: Daniel Kroening, dkr@amazon.com
 
 #include "state.h"
 
-optionalt<exprt> sentinel_dll_member(
+std::optional<exprt> sentinel_dll_member(
   const exprt &state,
   const exprt &node,
   bool next, // vs. prev
@@ -69,13 +69,13 @@ optionalt<exprt> sentinel_dll_member(
   return evaluate_exprt(state, field_address, component.type());
 }
 
-optionalt<exprt>
+std::optional<exprt>
 sentinel_dll_next(const exprt &state, const exprt &node, const namespacet &ns)
 {
   return sentinel_dll_member(state, node, true, ns);
 }
 
-optionalt<exprt>
+std::optional<exprt>
 sentinel_dll_prev(const exprt &state, const exprt &node, const namespacet &ns)
 {
   return sentinel_dll_member(state, node, false, ns);
diff --git a/src/cprover/sentinel_dll.h b/src/cprover/sentinel_dll.h
index 88331c6720d..8e5af2f8faf 100644
--- a/src/cprover/sentinel_dll.h
+++ b/src/cprover/sentinel_dll.h
@@ -101,10 +101,10 @@ inline state_is_sentinel_dll_exprt &to_state_is_sentinel_dll_expr(exprt &expr)
   return ret;
 }
 
-optionalt<exprt>
+std::optional<exprt>
 sentinel_dll_next(const exprt &state, const exprt &node, const namespacet &);
 
-optionalt<exprt>
+std::optional<exprt>
 sentinel_dll_prev(const exprt &state, const exprt &node, const namespacet &);
 
 #endif // CPROVER_CPROVER_SENTINEL_DLL_H
diff --git a/src/cprover/state_encoding.cpp b/src/cprover/state_encoding.cpp
index 2ea684d7fae..56ef744c049 100644
--- a/src/cprover/state_encoding.cpp
+++ b/src/cprover/state_encoding.cpp
@@ -1116,7 +1116,7 @@ void state_encodingt::encode(
 void state_encoding(
   const goto_modelt &goto_model,
   bool program_is_inlined,
-  optionalt<irep_idt> contract,
+  std::optional<irep_idt> contract,
   encoding_targett &dest)
 {
   if(program_is_inlined)
@@ -1179,7 +1179,7 @@ void state_encoding(
   const goto_modelt &goto_model,
   state_encoding_formatt state_encoding_format,
   bool program_is_inlined,
-  optionalt<irep_idt> contract,
+  std::optional<irep_idt> contract,
   std::ostream &out)
 {
   switch(state_encoding_format)
@@ -1236,7 +1236,7 @@ void variable_encoding(
 solver_resultt state_encoding_solver(
   const goto_modelt &goto_model,
   bool program_is_inlined,
-  optionalt<irep_idt> contract,
+  std::optional<irep_idt> contract,
   const solver_optionst &solver_options)
 {
   const namespacet ns(goto_model.symbol_table);
diff --git a/src/cprover/state_encoding.h b/src/cprover/state_encoding.h
index 96ce2ba0742..5042d628d1c 100644
--- a/src/cprover/state_encoding.h
+++ b/src/cprover/state_encoding.h
@@ -13,11 +13,11 @@ Author: Daniel Kroening, dkr@amazon.com
 #define CPROVER_CPROVER_STATE_ENCODING_H
 
 #include <util/irep.h>
-#include <util/optional.h>
 
 #include "solver.h"
 
 #include <iosfwd>
+#include <optional>
 
 class goto_modelt;
 
@@ -31,13 +31,13 @@ void state_encoding(
   const goto_modelt &,
   state_encoding_formatt,
   bool program_is_inlined,
-  optionalt<irep_idt> contract,
+  std::optional<irep_idt> contract,
   std::ostream &out);
 
 solver_resultt state_encoding_solver(
   const goto_modelt &,
   bool program_is_inlined,
-  optionalt<irep_idt> contract,
+  std::optional<irep_idt> contract,
   const solver_optionst &);
 
 void variable_encoding(
diff --git a/src/crangler/c_defines.h b/src/crangler/c_defines.h
index 3dc34ba435a..eb241ec4532 100644
--- a/src/crangler/c_defines.h
+++ b/src/crangler/c_defines.h
@@ -12,8 +12,7 @@ Author: Daniel Kroening, dkr@amazon.com
 #ifndef CPROVER_CRANGLER_C_DEFINES_H
 #define CPROVER_CRANGLER_C_DEFINES_H
 
-#include <util/optional.h>
-
+#include <optional>
 #include <string>
 #include <unordered_map>
 #include <vector>
@@ -25,7 +24,7 @@ class c_definest
 public:
   struct definet
   {
-    optionalt<std::vector<std::string>> parameters;
+    std::optional<std::vector<std::string>> parameters;
     std::string value;
   };
 
diff --git a/src/crangler/c_wrangler.cpp b/src/crangler/c_wrangler.cpp
index 7d716b745a4..2bb5f6b75a2 100644
--- a/src/crangler/c_wrangler.cpp
+++ b/src/crangler/c_wrangler.cpp
@@ -80,7 +80,7 @@ struct c_wranglert
     std::vector<function_contract_clauset> function_contract;
     std::vector<loop_contract_clauset> loop_contract;
     std::vector<assertiont> assertions;
-    optionalt<std::string> stub;
+    std::optional<std::string> stub;
     bool remove_static = false;
   };
 
diff --git a/src/crangler/mini_c_parser.cpp b/src/crangler/mini_c_parser.cpp
index dba474d1210..ce573ed166b 100644
--- a/src/crangler/mini_c_parser.cpp
+++ b/src/crangler/mini_c_parser.cpp
@@ -114,7 +114,7 @@ bool c_declarationt::has_body() const
   return !initializer.empty() && initializer.front() == '{';
 }
 
-optionalt<ctokent> c_declarationt::declared_identifier() const
+std::optional<ctokent> c_declarationt::declared_identifier() const
 {
   for(auto &t : declarator)
     if(is_identifier(t))
diff --git a/src/crangler/mini_c_parser.h b/src/crangler/mini_c_parser.h
index ab3930aae33..7453ec498af 100644
--- a/src/crangler/mini_c_parser.h
+++ b/src/crangler/mini_c_parser.h
@@ -12,11 +12,10 @@ Author: Daniel Kroening, dkr@amazon.com
 #ifndef CPROVER_CRANGLER_MINI_C_PARSER_H
 #define CPROVER_CRANGLER_MINI_C_PARSER_H
 
-#include <util/optional.h>
-
 #include "ctoken.h"
 
 #include <iosfwd>
+#include <optional>
 #include <vector>
 
 struct c_declarationt
@@ -32,7 +31,7 @@ struct c_declarationt
   void print(std::ostream &) const;
   bool is_function() const;
   bool has_body() const;
-  optionalt<ctokent> declared_identifier() const;
+  std::optional<ctokent> declared_identifier() const;
 };
 
 using c_translation_unitt = std::vector<c_declarationt>;
diff --git a/src/goto-analyzer/show_on_source.cpp b/src/goto-analyzer/show_on_source.cpp
index c6dc644b043..98f6d3889f9 100644
--- a/src/goto-analyzer/show_on_source.cpp
+++ b/src/goto-analyzer/show_on_source.cpp
@@ -17,7 +17,7 @@ Author: Daniel Kroening, kroening@kroening.com
 
 /// get the name of the file referred to at a location loc,
 /// if any
-static optionalt<std::string>
+static std::optional<std::string>
 show_location(const ai_baset &ai, ai_baset::locationt loc)
 {
   const auto abstract_state = ai.abstract_state_before(loc);
diff --git a/src/goto-analyzer/taint_analysis.cpp b/src/goto-analyzer/taint_analysis.cpp
index 45dd7b243df..55726c91e2b 100644
--- a/src/goto-analyzer/taint_analysis.cpp
+++ b/src/goto-analyzer/taint_analysis.cpp
@@ -42,7 +42,7 @@ class taint_analysist
     const symbol_tablet &,
     goto_functionst &,
     bool show_full,
-    const optionalt<std::string> &json_file_name);
+    const std::optional<std::string> &json_file_name);
 
 protected:
   messaget log;
@@ -226,7 +226,7 @@ bool taint_analysist::operator()(
   const symbol_tablet &symbol_table,
   goto_functionst &goto_functions,
   bool show_full,
-  const optionalt<std::string> &json_file_name)
+  const std::optional<std::string> &json_file_name)
 {
   try
   {
@@ -421,7 +421,7 @@ bool taint_analysis(
   const std::string &taint_file_name,
   message_handlert &message_handler,
   bool show_full,
-  const optionalt<std::string> &json_file_name)
+  const std::optional<std::string> &json_file_name)
 {
   taint_analysist taint_analysis(message_handler);
   return taint_analysis(
diff --git a/src/goto-analyzer/taint_analysis.h b/src/goto-analyzer/taint_analysis.h
index 841136a0413..6afb0899566 100644
--- a/src/goto-analyzer/taint_analysis.h
+++ b/src/goto-analyzer/taint_analysis.h
@@ -12,10 +12,9 @@ Author: Daniel Kroening, kroening@kroening.com
 #ifndef CPROVER_GOTO_ANALYZER_TAINT_ANALYSIS_H
 #define CPROVER_GOTO_ANALYZER_TAINT_ANALYSIS_H
 
+#include <optional>
 #include <string>
 
-#include <util/optional.h>
-
 class goto_modelt;
 class message_handlert;
 
@@ -24,6 +23,6 @@ bool taint_analysis(
   const std::string &taint_file_name,
   message_handlert &,
   bool show_full,
-  const optionalt<std::string> &json_output_file_name = {});
+  const std::optional<std::string> &json_output_file_name = {});
 
 #endif // CPROVER_GOTO_ANALYZER_TAINT_ANALYSIS_H
diff --git a/src/goto-analyzer/unreachable_instructions.cpp b/src/goto-analyzer/unreachable_instructions.cpp
index 6ff7822bed7..7afcf5c3223 100644
--- a/src/goto-analyzer/unreachable_instructions.cpp
+++ b/src/goto-analyzer/unreachable_instructions.cpp
@@ -100,7 +100,7 @@ static void add_to_xml(
   return;
 }
 
-static optionalt<std::string>
+static std::optional<std::string>
 file_name_string_opt(const source_locationt &source_location)
 {
   if(source_location.get_file().empty())
@@ -249,7 +249,7 @@ bool static_unreachable_instructions(
   return false;
 }
 
-static optionalt<std::string>
+static std::optional<std::string>
 line_string_opt(const source_locationt &source_location)
 {
   const irep_idt &line = source_location.get_line();
diff --git a/src/goto-cc/armcc_cmdline.cpp b/src/goto-cc/armcc_cmdline.cpp
index b5c2cae696a..6b55671caa5 100644
--- a/src/goto-cc/armcc_cmdline.cpp
+++ b/src/goto-cc/armcc_cmdline.cpp
@@ -269,7 +269,7 @@ static const std::vector<std::string> options_with_arg
 };
 // clang-format on
 
-optionalt<std::string>
+std::optional<std::string>
 prefix_in_list(const std::string &option, const std::vector<std::string> &list)
 {
   const auto found =
@@ -293,7 +293,7 @@ bool armcc_cmdlinet::parse(int argc, const char **argv)
     }
 
     // it starts with - and it isn't "-"
-    optionalt<std::string> prefix;
+    std::optional<std::string> prefix;
 
     if(in_list(argv[i], options_no_arg))
     {
diff --git a/src/goto-cc/compile.cpp b/src/goto-cc/compile.cpp
index 3d76ace4579..730cfba7956 100644
--- a/src/goto-cc/compile.cpp
+++ b/src/goto-cc/compile.cpp
@@ -307,7 +307,7 @@ bool compilet::find_library(const std::string &name)
 
 /// parses object files and links them
 /// \return true on error, false otherwise
-bool compilet::link(optionalt<symbol_tablet> &&symbol_table)
+bool compilet::link(std::optional<symbol_tablet> &&symbol_table)
 {
   // "compile" hitherto uncompiled functions
   log.statistics() << "Compiling functions" << messaget::eom;
@@ -361,7 +361,7 @@ bool compilet::link(optionalt<symbol_tablet> &&symbol_table)
 /// Parses source files and writes object files, or keeps the symbols in the
 /// symbol_table if not compiling/assembling only.
 /// \return Symbol table, if parsing and type checking succeeded, else empty
-optionalt<symbol_tablet> compilet::compile()
+std::optional<symbol_tablet> compilet::compile()
 {
   symbol_tablet symbol_table;
 
@@ -606,7 +606,8 @@ bool compilet::write_bin_object_file(
 
 /// Parses and type checks a source file located at \p file_name.
 /// \return A symbol table if, and only if, parsing and type checking succeeded.
-optionalt<symbol_tablet> compilet::parse_source(const std::string &file_name)
+std::optional<symbol_tablet>
+compilet::parse_source(const std::string &file_name)
 {
   language_filest language_files;
 
diff --git a/src/goto-cc/compile.h b/src/goto-cc/compile.h
index f8480649a48..3eb20174f0e 100644
--- a/src/goto-cc/compile.h
+++ b/src/goto-cc/compile.h
@@ -64,10 +64,10 @@ class compilet
   bool parse(const std::string &filename, language_filest &);
   bool parse_stdin(languaget &);
   bool doit();
-  optionalt<symbol_tablet> compile();
-  bool link(optionalt<symbol_tablet> &&symbol_table);
+  std::optional<symbol_tablet> compile();
+  bool link(std::optional<symbol_tablet> &&symbol_table);
 
-  optionalt<symbol_tablet> parse_source(const std::string &);
+  std::optional<symbol_tablet> parse_source(const std::string &);
 
   /// Writes the goto functions of \p src_goto_model to a binary format object
   /// file.
diff --git a/src/goto-cc/goto_cc_cmdline.cpp b/src/goto-cc/goto_cc_cmdline.cpp
index 722bc87148a..8d997a466d0 100644
--- a/src/goto-cc/goto_cc_cmdline.cpp
+++ b/src/goto-cc/goto_cc_cmdline.cpp
@@ -48,7 +48,7 @@ bool goto_cc_cmdlinet::in_list(const char *option, const char **list)
 
 std::size_t goto_cc_cmdlinet::get_optnr(const std::string &opt_string)
 {
-  optionalt<std::size_t> optnr;
+  std::optional<std::size_t> optnr;
   cmdlinet::optiont option;
 
   if(has_prefix(opt_string, "--")) // starts with -- ?
diff --git a/src/goto-cc/ms_cl_cmdline.cpp b/src/goto-cc/ms_cl_cmdline.cpp
index fd43edccb85..fe4edcf1295 100644
--- a/src/goto-cc/ms_cl_cmdline.cpp
+++ b/src/goto-cc/ms_cl_cmdline.cpp
@@ -425,7 +425,7 @@ void ms_cl_cmdlinet::process_cl_option(const std::string &s)
     if(std::string(s, 1, std::string::npos)==ms_cl_flags[j])
     {
       cmdlinet::optiont option;
-      optionalt<std::size_t> optnr;
+      std::optional<std::size_t> optnr;
 
       if(s.size()==2)
       {
@@ -461,7 +461,7 @@ void ms_cl_cmdlinet::process_cl_option(const std::string &s)
     {
       cmdlinet::optiont option;
 
-      optionalt<std::size_t> optnr;
+      std::optional<std::size_t> optnr;
 
       if(ms_cl_prefix.size()==1)
       {
diff --git a/src/goto-cc/ms_link_cmdline.cpp b/src/goto-cc/ms_link_cmdline.cpp
index 5e63c9b13d1..ddf5ae3d8c1 100644
--- a/src/goto-cc/ms_link_cmdline.cpp
+++ b/src/goto-cc/ms_link_cmdline.cpp
@@ -335,7 +335,7 @@ void ms_link_cmdlinet::process_link_option(const std::string &s)
       to_upper_string(std::string(s, 1, std::string::npos)) == ms_link_option ||
       to_upper_string(std::string(s, 1, ms_link_option.size() + 1)) == ms_link_option + ':')
     {
-      optionalt<std::size_t> optnr = getoptnr(ms_link_option);
+      std::optional<std::size_t> optnr = getoptnr(ms_link_option);
 
       if(!optnr.has_value())
       {
diff --git a/src/goto-harness/memory_snapshot_harness_generator.h b/src/goto-harness/memory_snapshot_harness_generator.h
index ccfd3d7abf2..52a51fc2560 100644
--- a/src/goto-harness/memory_snapshot_harness_generator.h
+++ b/src/goto-harness/memory_snapshot_harness_generator.h
@@ -9,8 +9,6 @@ Author: Daniel Poetzl
 #ifndef CPROVER_GOTO_HARNESS_MEMORY_SNAPSHOT_HARNESS_GENERATOR_H
 #define CPROVER_GOTO_HARNESS_MEMORY_SNAPSHOT_HARNESS_GENERATOR_H
 
-#include <util/optional.h>
-
 #include <goto-programs/goto_program.h>
 
 #include "goto_harness_generator.h"
@@ -55,7 +53,7 @@ class memory_snapshot_harness_generatort : public goto_harness_generatort
   struct entry_goto_locationt
   {
     irep_idt function_name;
-    optionalt<unsigned> location_number;
+    std::optional<unsigned> location_number;
 
     entry_goto_locationt() = delete;
     explicit entry_goto_locationt(irep_idt function_name)
@@ -317,7 +315,7 @@ class memory_snapshot_harness_generatort : public goto_harness_generatort
         searchable_input[item.first] = item.second;
       }
       auto associate_key_with_t =
-        [&searchable_input](const Key &key) -> optionalt<valuet> {
+        [&searchable_input](const Key &key) -> std::optional<valuet> {
         if(searchable_input.count(key) != 0)
           return valuet(key, searchable_input[key]);
         else
diff --git a/src/goto-harness/recursive_initialization.cpp b/src/goto-harness/recursive_initialization.cpp
index 28e86da5832..79bc6bfedc0 100644
--- a/src/goto-harness/recursive_initialization.cpp
+++ b/src/goto-harness/recursive_initialization.cpp
@@ -246,8 +246,8 @@ code_blockt build_null_pointer(const symbol_exprt &result_symbol)
 code_blockt recursive_initializationt::build_constructor_body(
   const exprt &depth_symbol,
   const symbol_exprt &result_symbol,
-  const optionalt<exprt> &size_symbol,
-  const optionalt<irep_idt> &lhs_name,
+  const std::optional<exprt> &size_symbol,
+  const std::optional<irep_idt> &lhs_name,
   const bool is_nullable)
 {
   PRECONDITION(result_symbol.type().id() == ID_pointer);
@@ -297,8 +297,8 @@ irep_idt recursive_initializationt::build_constructor(const exprt &expr)
   // or in case a `size` is associated with the `expr`
   //
   // void type_constructor_T(int depth_T, T *result_T, int *size);
-  optionalt<irep_idt> size_var;
-  optionalt<irep_idt> expr_name;
+  std::optional<irep_idt> size_var;
+  std::optional<irep_idt> expr_name;
   bool is_nullable = false;
   bool has_size_param = false;
   if(expr.id() == ID_symbol)
@@ -335,7 +335,7 @@ irep_idt recursive_initializationt::build_constructor(const exprt &expr)
   fun_params.push_back(result_parameter);
 
   auto &symbol_table = goto_model.symbol_table;
-  optionalt<exprt> size_symbol_expr;
+  std::optional<exprt> size_symbol_expr;
   if(expr_name.has_value() && should_be_treated_as_array(*expr_name))
   {
     typet size_var_type;
@@ -397,7 +397,7 @@ bool recursive_initializationt::should_be_treated_as_array(
          initialization_config.pointers_to_treat_as_arrays.end();
 }
 
-optionalt<recursive_initializationt::equal_cluster_idt>
+std::optional<recursive_initializationt::equal_cluster_idt>
 recursive_initializationt::find_equal_cluster(const irep_idt &name) const
 {
   for(equal_cluster_idt index = 0;
@@ -418,7 +418,7 @@ bool recursive_initializationt::is_array_size_parameter(
          initialization_config.variables_that_hold_array_sizes.end();
 }
 
-optionalt<irep_idt> recursive_initializationt::get_associated_size_variable(
+std::optional<irep_idt> recursive_initializationt::get_associated_size_variable(
   const irep_idt &array_name) const
 {
   return optional_lookup(
@@ -680,7 +680,7 @@ code_blockt recursive_initializationt::build_pointer_constructor(
     depth, ID_ge, get_symbol_expr(max_depth_var_name)};
   exprt::operandst should_not_recurse{depth_gt_max_depth};
 
-  optionalt<symbol_exprt> has_seen;
+  std::optional<symbol_exprt> has_seen;
   if(can_cast_type<struct_tag_typet>(to_pointer_type(type).base_type()))
     has_seen = get_fresh_global_symexpr(
       "has_seen_" + type2id(to_pointer_type(type).base_type()));
@@ -820,7 +820,7 @@ code_blockt recursive_initializationt::build_dynamic_array_constructor(
   const exprt &depth,
   const symbol_exprt &result,
   const exprt &size,
-  const optionalt<irep_idt> &lhs_name)
+  const std::optional<irep_idt> &lhs_name)
 {
   PRECONDITION(result.type().id() == ID_pointer);
   const typet &dynamic_array_type = to_pointer_type(result.type()).base_type();
diff --git a/src/goto-harness/recursive_initialization.h b/src/goto-harness/recursive_initialization.h
index bf7ed32036f..04a30a19700 100644
--- a/src/goto-harness/recursive_initialization.h
+++ b/src/goto-harness/recursive_initialization.h
@@ -14,7 +14,6 @@ Author: Diffblue Ltd.
 #include <unordered_set>
 
 #include <util/cprover_prefix.h>
-#include <util/optional.h>
 #include <util/prefix.h>
 #include <util/std_expr.h>
 #include <util/symbol.h>
@@ -123,7 +122,7 @@ class recursive_initializationt
   irep_idt max_depth_var_name;
   irep_idt min_depth_var_name;
   type_constructor_namest type_constructor_names;
-  std::vector<optionalt<exprt>> common_arguments_origins;
+  std::vector<std::optional<exprt>> common_arguments_origins;
 
   /// Get the malloc function as symbol exprt,
   /// and inserts it into the goto-model if it doesn't
@@ -131,9 +130,10 @@ class recursive_initializationt
   symbol_exprt get_malloc_function();
 
   bool should_be_treated_as_array(const irep_idt &pointer_name) const;
-  optionalt<equal_cluster_idt> find_equal_cluster(const irep_idt &name) const;
+  std::optional<equal_cluster_idt>
+  find_equal_cluster(const irep_idt &name) const;
   bool is_array_size_parameter(const irep_idt &cmdline_arg) const;
-  optionalt<irep_idt>
+  std::optional<irep_idt>
   get_associated_size_variable(const irep_idt &array_name) const;
   bool should_be_treated_as_cstring(const irep_idt &pointer_name) const;
 
@@ -201,8 +201,8 @@ class recursive_initializationt
   code_blockt build_constructor_body(
     const exprt &depth_symbol,
     const symbol_exprt &result_symbol,
-    const optionalt<exprt> &size_symbol,
-    const optionalt<irep_idt> &lhs_name,
+    const std::optional<exprt> &size_symbol,
+    const std::optional<irep_idt> &lhs_name,
     const bool is_nullable);
 
   /// Check if a constructor for the type of \p expr already exists and create
@@ -260,7 +260,7 @@ class recursive_initializationt
     const exprt &depth,
     const symbol_exprt &result,
     const exprt &size,
-    const optionalt<irep_idt> &lhs_name);
+    const std::optional<irep_idt> &lhs_name);
 
   /// Select the specified struct-member to be non-deterministically
   ///   initialized.
diff --git a/src/goto-instrument/accelerate/disjunctive_polynomial_acceleration.cpp b/src/goto-instrument/accelerate/disjunctive_polynomial_acceleration.cpp
index 6bbf16a92cc..954be5565e6 100644
--- a/src/goto-instrument/accelerate/disjunctive_polynomial_acceleration.cpp
+++ b/src/goto-instrument/accelerate/disjunctive_polynomial_acceleration.cpp
@@ -640,7 +640,7 @@ void disjunctive_polynomial_accelerationt::assert_for_values(
   exprt &target)
 {
   // First figure out what the appropriate type for this expression is.
-  optionalt<typet> expr_type;
+  std::optional<typet> expr_type;
 
   for(std::map<exprt, exprt>::iterator it=values.begin();
       it!=values.end();
diff --git a/src/goto-instrument/accelerate/polynomial.cpp b/src/goto-instrument/accelerate/polynomial.cpp
index 789ae0b5b41..e9f4f910b04 100644
--- a/src/goto-instrument/accelerate/polynomial.cpp
+++ b/src/goto-instrument/accelerate/polynomial.cpp
@@ -22,7 +22,7 @@ Author: Matt Lewis
 exprt polynomialt::to_expr()
 {
   exprt ret=nil_exprt();
-  optionalt<typet> itype;
+  std::optional<typet> itype;
 
   // Figure out the appropriate type to do all the intermediate calculations
   // in.
diff --git a/src/goto-instrument/accelerate/polynomial_accelerator.cpp b/src/goto-instrument/accelerate/polynomial_accelerator.cpp
index 801821b7674..41a88788c58 100644
--- a/src/goto-instrument/accelerate/polynomial_accelerator.cpp
+++ b/src/goto-instrument/accelerate/polynomial_accelerator.cpp
@@ -497,7 +497,7 @@ void polynomial_acceleratort::assert_for_values(
   overflow_instrumentert &overflow)
 {
   // First figure out what the appropriate type for this expression is.
-  optionalt<typet> expr_type;
+  std::optional<typet> expr_type;
 
   for(std::map<exprt, int>::iterator it=values.begin();
       it!=values.end();
diff --git a/src/goto-instrument/concurrency.cpp b/src/goto-instrument/concurrency.cpp
index 877b49b3651..90daf39c4a0 100644
--- a/src/goto-instrument/concurrency.cpp
+++ b/src/goto-instrument/concurrency.cpp
@@ -58,14 +58,14 @@ class concurrency_instrumentationt
   {
   public:
     typet type;
-    optionalt<symbol_exprt> array_symbol, w_index_symbol;
+    std::optional<symbol_exprt> array_symbol, w_index_symbol;
   };
 
   class thread_local_vart
   {
   public:
     typet type;
-    optionalt<symbol_exprt> array_symbol;
+    std::optional<symbol_exprt> array_symbol;
   };
 
   typedef std::map<irep_idt, shared_vart> shared_varst;
diff --git a/src/goto-instrument/contracts/contracts.cpp b/src/goto-instrument/contracts/contracts.cpp
index a140797eabc..8b9e9ee23e8 100644
--- a/src/goto-instrument/contracts/contracts.cpp
+++ b/src/goto-instrument/contracts/contracts.cpp
@@ -625,7 +625,7 @@ void code_contractst::apply_function_contract(
   exprt::operandst instantiation_values;
 
   // keep track of the call's return expression to make it nondet later
-  optionalt<exprt> call_ret_opt = {};
+  std::optional<exprt> call_ret_opt = {};
 
   // if true, the call return variable variable was created during replacement
   bool call_ret_is_fresh_var = false;
@@ -1272,7 +1272,7 @@ void code_contractst::add_contract_check(
   source_location.set_function(wrapper_function);
 
   // decl ret
-  optionalt<code_returnt> return_stmt;
+  std::optional<code_returnt> return_stmt;
   if(code_type.return_type() != empty_typet())
   {
     symbol_exprt r = get_fresh_aux_symbol(
diff --git a/src/goto-instrument/contracts/contracts_wrangler.cpp b/src/goto-instrument/contracts/contracts_wrangler.cpp
index 62c040006a9..b3aab30e54c 100644
--- a/src/goto-instrument/contracts/contracts_wrangler.cpp
+++ b/src/goto-instrument/contracts/contracts_wrangler.cpp
@@ -158,7 +158,7 @@ void contracts_wranglert::mangle(
               << log.eom;
 
   // Extract the assigns from parse_tree.
-  optionalt<exprt> assigns_expr;
+  std::optional<exprt> assigns_expr;
   if(!loop_contracts.assigns.empty())
   {
     assigns_expr = static_cast<exprt &>(ansi_c_parser.parse_tree.items.front()
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc.cpp
index db97996db2b..4adf164a203 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc.cpp
@@ -16,7 +16,6 @@ Author: Remi Delmas, delmarsd@amazon.com
 #include <util/mathematical_expr.h>
 #include <util/mathematical_types.h>
 #include <util/namespace.h>
-#include <util/optional.h>
 #include <util/pointer_expr.h>
 #include <util/pointer_offset_size.h>
 #include <util/pointer_predicates.h>
@@ -117,7 +116,7 @@ void dfcc(
   const optionst &options,
   goto_modelt &goto_model,
   const irep_idt &harness_id,
-  const optionalt<irep_idt> &to_check,
+  const std::optional<irep_idt> &to_check,
   const bool allow_recursive_calls,
   const std::set<irep_idt> &to_replace,
   const bool apply_loop_contracts,
@@ -134,7 +133,7 @@ void dfcc(
     goto_model,
     harness_id,
     to_check.has_value() ? parse_function_contract_pair(to_check.value())
-                         : optionalt<std::pair<irep_idt, irep_idt>>{},
+                         : std::optional<std::pair<irep_idt, irep_idt>>{},
     allow_recursive_calls,
     to_replace_map,
     apply_loop_contracts,
@@ -147,7 +146,7 @@ void dfcc(
   const optionst &options,
   goto_modelt &goto_model,
   const irep_idt &harness_id,
-  const optionalt<std::pair<irep_idt, irep_idt>> &to_check,
+  const std::optional<std::pair<irep_idt, irep_idt>> &to_check,
   const bool allow_recursive_calls,
   const std::map<irep_idt, irep_idt> &to_replace,
   const bool apply_loop_contracts,
@@ -172,7 +171,7 @@ dfcct::dfcct(
   const optionst &options,
   goto_modelt &goto_model,
   const irep_idt &harness_id,
-  const optionalt<std::pair<irep_idt, irep_idt>> &to_check,
+  const std::optional<std::pair<irep_idt, irep_idt>> &to_check,
   const bool allow_recursive_calls,
   const std::map<irep_idt, irep_idt> &to_replace,
   const dfcc_loop_contract_modet loop_contract_mode,
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc.h b/src/goto-instrument/contracts/dynamic-frames/dfcc.h
index 88499b41e44..247c70cf127 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc.h
@@ -106,7 +106,7 @@ void dfcc(
   const optionst &options,
   goto_modelt &goto_model,
   const irep_idt &harness_id,
-  const optionalt<irep_idt> &to_check,
+  const std::optional<irep_idt> &to_check,
   const bool allow_recursive_calls,
   const std::set<irep_idt> &to_replace,
   const bool apply_loop_contracts,
@@ -139,7 +139,7 @@ void dfcc(
   const optionst &options,
   goto_modelt &goto_model,
   const irep_idt &harness_id,
-  const optionalt<std::pair<irep_idt, irep_idt>> &to_check,
+  const std::optional<std::pair<irep_idt, irep_idt>> &to_check,
   const bool allow_recursive_calls,
   const std::map<irep_idt, irep_idt> &to_replace,
   const bool apply_loop_contracts,
@@ -167,7 +167,7 @@ class dfcct
     const optionst &options,
     goto_modelt &goto_model,
     const irep_idt &harness_id,
-    const optionalt<std::pair<irep_idt, irep_idt>> &to_check,
+    const std::optional<std::pair<irep_idt, irep_idt>> &to_check,
     const bool allow_recursive_calls,
     const std::map<irep_idt, irep_idt> &to_replace,
     const dfcc_loop_contract_modet loop_contract_mode,
@@ -204,7 +204,7 @@ class dfcct
   const optionst &options;
   goto_modelt &goto_model;
   const irep_idt &harness_id;
-  const optionalt<std::pair<irep_idt, irep_idt>> &to_check;
+  const std::optional<std::pair<irep_idt, irep_idt>> &to_check;
   const bool allow_recursive_calls;
   const std::map<irep_idt, irep_idt> &to_replace;
   const dfcc_loop_contract_modet loop_contract_mode;
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.cpp
index 7eb14538971..69073bbc192 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.cpp
@@ -120,7 +120,7 @@ void dfcc_loop_infot::output(std::ostream &out) const
   out << "}\n";
 }
 
-optionalt<goto_programt::targett>
+std::optional<goto_programt::targett>
 dfcc_loop_infot::find_head(goto_programt &goto_program) const
 {
   for(auto target = goto_program.instructions.begin();
@@ -135,10 +135,10 @@ dfcc_loop_infot::find_head(goto_programt &goto_program) const
   return {};
 }
 
-optionalt<goto_programt::targett>
+std::optional<goto_programt::targett>
 dfcc_loop_infot::find_latch(goto_programt &goto_program) const
 {
-  optionalt<goto_programt::targett> result = std::nullopt;
+  std::optional<goto_programt::targett> result = std::nullopt;
   for(auto target = goto_program.instructions.begin();
       target != goto_program.instructions.end();
       target++)
@@ -152,7 +152,7 @@ dfcc_loop_infot::find_latch(goto_programt &goto_program) const
   return result;
 }
 
-static optionalt<goto_programt::targett> check_has_contract_rec(
+static std::optional<goto_programt::targett> check_has_contract_rec(
   const dfcc_loop_nesting_grapht &loop_nesting_graph,
   const std::size_t loop_idx,
   const bool must_have_contract)
@@ -174,7 +174,7 @@ static optionalt<goto_programt::targett> check_has_contract_rec(
 /// Traverses the loop nesting graph from top level loops and checks if all
 /// loops nested in loops that have contracts also have contracts.
 /// Return the head of the first offending loop if it exists, nothing otherwise.
-static optionalt<goto_programt::targett> check_inner_loops_have_contracts(
+static std::optional<goto_programt::targett> check_inner_loops_have_contracts(
   const dfcc_loop_nesting_grapht &loop_nesting_graph)
 {
   for(std::size_t idx = 0; idx < loop_nesting_graph.size(); idx++)
@@ -710,7 +710,7 @@ dfcc_cfg_infot::get_loop_info(const std::size_t loop_id) const
 }
 
 // find the identifier or the immediately enclosing loop in topological order
-const optionalt<std::size_t>
+const std::optional<std::size_t>
 dfcc_cfg_infot::get_outer_loop_identifier(const std::size_t loop_id) const
 {
   PRECONDITION(is_valid_loop_id(loop_id));
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.h
index 03b0e776fbb..3cbd23551a6 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_cfg_info.h
@@ -92,7 +92,7 @@ class dfcc_loop_infot
   /// instrumented in any other manner that might not maintain or copy the
   /// source location tags properly then nothing of the argument above is
   /// expected to hold anymore and you then use this method at your own risk.
-  optionalt<goto_programt::targett>
+  std::optional<goto_programt::targett>
   find_head(goto_programt &goto_program) const;
 
   // Finds the last instruction tagged as loop latch and having the same loop
@@ -104,7 +104,7 @@ class dfcc_loop_infot
   // in the program and turning loops into non-loops. For an explanation of why
   // this would work please read the documentation of find head, and mentally
   // replace `head` by `latch` and `start` by `end` in the explanation.
-  optionalt<goto_programt::targett>
+  std::optional<goto_programt::targett>
   find_latch(goto_programt &goto_program) const;
 
   /// Loop identifier assigned by DFCC to this loop.
@@ -272,7 +272,7 @@ class dfcc_cfg_infot
 
   /// Finds the DFCC id of the loop that contains the given loop, returns
   /// nullopt when the loop has no outer loop.
-  const optionalt<std::size_t>
+  const std::optional<std::size_t>
   get_outer_loop_identifier(const std::size_t loop_id) const;
 
   /// True iff a DECL ident must be tracked in the write set of the loop
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_clauses_codegen.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_clauses_codegen.h
index 09cf3cd0143..1bd4ab125bd 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_clauses_codegen.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_clauses_codegen.h
@@ -18,7 +18,6 @@ Date: February 2023
 
 #include <util/message.h>
 #include <util/namespace.h>
-#include <util/optional.h>
 #include <util/std_expr.h>
 
 #include "dfcc_contract_mode.h"
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_functions.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_functions.h
index f274aa5f8f0..963dc5fdf60 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_functions.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_functions.h
@@ -18,7 +18,6 @@ Date: August 2022
 
 #include <util/message.h>
 #include <util/namespace.h>
-#include <util/optional.h>
 #include <util/std_expr.h>
 
 #include "dfcc_contract_mode.h"
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.cpp
index c3add8fb8ed..245f45bcfb3 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.cpp
@@ -110,7 +110,7 @@ void dfcc_contract_handlert::add_contract_instructions(
 
 const symbolt &dfcc_contract_handlert::get_pure_contract_symbol(
   const irep_idt &contract_id,
-  const optionalt<irep_idt> function_id_opt)
+  const std::optional<irep_idt> function_id_opt)
 {
   auto pure_contract_id = "contract::" + id2string(contract_id);
   const symbolt *pure_contract_symbol = nullptr;
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.h
index 51020c9547e..0f77b883876 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_contract_handler.h
@@ -17,7 +17,6 @@ Date: August 2022
 
 #include <util/message.h>
 #include <util/namespace.h>
-#include <util/optional.h>
 #include <util/std_expr.h>
 
 #include "dfcc_contract_functions.h"
@@ -111,7 +110,7 @@ class dfcc_contract_handlert
   /// PRECONDITION is triggered.
   const symbolt &get_pure_contract_symbol(
     const irep_idt &contract_id,
-    const optionalt<irep_idt> function_id_opt = {});
+    const std::optional<irep_idt> function_id_opt = {});
 
 protected:
   goto_modelt &goto_model;
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp
index ec5a7e8d082..1f885938aca 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp
@@ -752,7 +752,7 @@ void dfcc_instrumentt::instrument_lhs(
 /// Checks if lhs is the `dead_object`, and if the rhs
 /// is an `if_exprt(nondet, ptr, dead_object)` expression.
 /// Returns `ptr` if the pattern was matched, nullptr otherwise.
-optionalt<exprt>
+std::optional<exprt>
 dfcc_instrumentt::is_dead_object_update(const exprt &lhs, const exprt &rhs)
 {
   if(
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.h
index a65aaece8c0..4dd9aeec881 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.h
@@ -286,7 +286,8 @@ class dfcc_instrumentt
   /// is an `if_exprt(nondet, ptr, dead_object)` expression.
   /// Returns a pointer to the `ptr` expression if the pattern was matched,
   /// returns `nullptr` otherwise.
-  optionalt<exprt> is_dead_object_update(const exprt &lhs, const exprt &rhs);
+  std::optional<exprt>
+  is_dead_object_update(const exprt &lhs, const exprt &rhs);
 
   /// Instrument the \p lhs of an `ASSIGN lhs := rhs` instruction by
   /// adding an inclusion check of \p lhs in \p write_set.
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_library.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_library.cpp
index c4c5e8902bc..4dcb8c9316d 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_library.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_library.cpp
@@ -203,7 +203,7 @@ dfcc_funt dfcc_libraryt::get_hook(const irep_idt &function_id) const
 }
 
 // Returns the havoc function to use for a given front-end function
-optionalt<dfcc_funt>
+std::optional<dfcc_funt>
 dfcc_libraryt::get_havoc_hook(const irep_idt &function_id) const
 {
   auto found = havoc_hook.find(function_id);
@@ -362,7 +362,7 @@ void dfcc_libraryt::load(std::set<irep_idt> &to_instrument)
     goto_model.goto_functions.function_map.at(it.second.name).make_hidden();
 }
 
-optionalt<dfcc_funt> dfcc_libraryt::get_dfcc_fun(const irep_idt &id) const
+std::optional<dfcc_funt> dfcc_libraryt::get_dfcc_fun(const irep_idt &id) const
 {
   auto found = dfcc_name_to_fun.find(id);
   if(found != dfcc_name_to_fun.end())
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_library.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_library.h
index 615d88785d4..aa49b9fe536 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_library.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_library.h
@@ -14,7 +14,6 @@ Author: Remi Delmas, delmasrd@amazon.com
 
 #include <util/irep.h>
 #include <util/message.h>
-#include <util/optional.h>
 
 #include <goto-programs/goto_instruction_code.h>
 
@@ -223,7 +222,7 @@ class dfcc_libraryt
   void load(std::set<irep_idt> &to_instrument);
 
   /// Returns the dfcc_funt that corresponds to the given id if any.
-  optionalt<dfcc_funt> get_dfcc_fun(const irep_idt &id) const;
+  std::optional<dfcc_funt> get_dfcc_fun(const irep_idt &id) const;
 
   /// Returns the name of the given dfcc_funt.
   const irep_idt &get_dfcc_fun_name(dfcc_funt fun) const;
@@ -264,7 +263,7 @@ class dfcc_libraryt
   /// Returns the library instrumentation hook for the given built-in.
   /// function_id must be one of `__CPROVER_assignable`,
   /// `__CPROVER_object_whole`, `__CPROVER_object_from`, `__CPROVER_object_upto`
-  optionalt<dfcc_funt> get_havoc_hook(const irep_idt &function_id) const;
+  std::optional<dfcc_funt> get_havoc_hook(const irep_idt &function_id) const;
 
   /// \brief Returns the "__dfcc_instrumented_functions" symbol or creates it if
   /// it does not exist already.
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_lift_memory_predicates.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_lift_memory_predicates.cpp
index 3669ab3c183..2a1429234c3 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_lift_memory_predicates.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_lift_memory_predicates.cpp
@@ -180,7 +180,7 @@ std::set<irep_idt> dfcc_lift_memory_predicatest::lift_predicates(
 }
 
 // returns an optional rank
-static optionalt<std::size_t> is_param_expr(
+static std::optional<std::size_t> is_param_expr(
   const exprt &expr,
   const std::map<irep_idt, std::size_t> &parameter_rank)
 {
@@ -331,7 +331,7 @@ void dfcc_lift_memory_predicatest::lift_parameters_and_update_body(
     // rewrite all occurrences of lifted parameters
     instruction.transform([&replace_lifted_params](exprt expr) {
       const bool changed = !replace_lifted_params.replace(expr);
-      return changed ? optionalt<exprt>{expr} : std::nullopt;
+      return changed ? std::optional<exprt>{expr} : std::nullopt;
     });
 
     // add address-of to all arguments expressions passed in lifted position to
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.cpp
index a9ba9ad9c1b..6f1be29ad7d 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.cpp
@@ -23,7 +23,7 @@ void dfcc_set_loop_id(
   target->source_location_nonconst().set(ID_loop_id, loop_id);
 }
 
-optionalt<std::size_t>
+std::optional<std::size_t>
 dfcc_get_loop_id(const goto_programt::instructiont::const_targett &target)
 {
   if(target->source_location().get(ID_loop_id).empty())
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.h
index ab28a2c0d93..98d33d5d34f 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_loop_tags.h
@@ -24,7 +24,7 @@ bool dfcc_has_loop_id(
   const goto_programt::instructiont::const_targett &target,
   std::size_t loop_id);
 
-optionalt<std::size_t>
+std::optional<std::size_t>
 dfcc_get_loop_id(const goto_programt::instructiont::const_targett &target);
 
 void dfcc_set_loop_head(goto_programt::instructiont::targett &target);
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_swap_and_wrap.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_swap_and_wrap.cpp
index 8a74801b169..642aa105604 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_swap_and_wrap.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_swap_and_wrap.cpp
@@ -16,7 +16,6 @@ Author: Remi Delmas, delmarsd@amazon.com
 #include <util/mathematical_expr.h>
 #include <util/mathematical_types.h>
 #include <util/namespace.h>
-#include <util/optional.h>
 #include <util/pointer_expr.h>
 #include <util/pointer_offset_size.h>
 #include <util/pointer_predicates.h>
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.cpp b/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.cpp
index 703515a5ead..4df01f60750 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.cpp
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.cpp
@@ -301,7 +301,7 @@ const symbolt &dfcc_utilst::clone_and_rename_function(
   goto_modelt &goto_model,
   const irep_idt &function_id,
   const irep_idt &new_function_id,
-  optionalt<typet> new_return_type = {})
+  std::optional<typet> new_return_type = {})
 {
   std::function<const irep_idt(const irep_idt &)> trans_fun =
     [&](const irep_idt &old_name) { return new_function_id; };
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.h
index 2b0bec8dbcb..7923947bd4f 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_utils.h
@@ -104,7 +104,7 @@ struct dfcc_utilst
     goto_modelt &goto_model,
     const irep_idt &function_id,
     const irep_idt &new_function_id,
-    optionalt<typet> new_return_type);
+    std::optional<typet> new_return_type);
 
   /// Given a function to wrap `foo` and a new name `wrapped_foo`
   ///
diff --git a/src/goto-instrument/contracts/dynamic-frames/dfcc_wrapper_program.h b/src/goto-instrument/contracts/dynamic-frames/dfcc_wrapper_program.h
index 09ff311dbfa..945999f9bfd 100644
--- a/src/goto-instrument/contracts/dynamic-frames/dfcc_wrapper_program.h
+++ b/src/goto-instrument/contracts/dynamic-frames/dfcc_wrapper_program.h
@@ -17,7 +17,6 @@ Author: Remi Delmas, delmasrd@amazon.com
 
 #include <util/message.h>
 #include <util/namespace.h>
-#include <util/optional.h>
 #include <util/std_expr.h>
 
 #include "dfcc_contract_functions.h"
@@ -139,7 +138,7 @@ class dfcc_wrapper_programt
   const source_locationt wrapper_sl;
 
   /// Symbol for the return value of the wrapped function
-  optionalt<symbol_exprt> return_value_opt;
+  std::optional<symbol_exprt> return_value_opt;
 
   /// Symbol for the write set object derived from the contract
   const symbol_exprt contract_write_set;
diff --git a/src/goto-instrument/cover_basic_blocks.cpp b/src/goto-instrument/cover_basic_blocks.cpp
index c290a1c3ce9..36af6b16964 100644
--- a/src/goto-instrument/cover_basic_blocks.cpp
+++ b/src/goto-instrument/cover_basic_blocks.cpp
@@ -13,7 +13,7 @@ Author: Peter Schrammel
 
 #include <util/message.h>
 
-optionalt<std::size_t> cover_basic_blockst::continuation_of_block(
+std::optional<std::size_t> cover_basic_blockst::continuation_of_block(
   const goto_programt::const_targett &instruction,
   cover_basic_blockst::block_mapt &block_map)
 {
@@ -103,7 +103,7 @@ std::size_t cover_basic_blockst::block_of(goto_programt::const_targett t) const
   return it->second;
 }
 
-optionalt<goto_programt::const_targett>
+std::optional<goto_programt::const_targett>
 cover_basic_blockst::instruction_of(const std::size_t block_nr) const
 {
   INVARIANT(block_nr < block_infos.size(), "block number out of range");
@@ -214,7 +214,7 @@ cover_basic_blocks_javat::block_of(goto_programt::const_targett t) const
   return it->second;
 }
 
-optionalt<goto_programt::const_targett>
+std::optional<goto_programt::const_targett>
 cover_basic_blocks_javat::instruction_of(const std::size_t block_nr) const
 {
   PRECONDITION(block_nr < block_infos.size());
diff --git a/src/goto-instrument/cover_basic_blocks.h b/src/goto-instrument/cover_basic_blocks.h
index 5fe8b5b9767..8c9bd2c2a89 100644
--- a/src/goto-instrument/cover_basic_blocks.h
+++ b/src/goto-instrument/cover_basic_blocks.h
@@ -12,8 +12,6 @@ Author: Daniel Kroening
 #ifndef CPROVER_GOTO_INSTRUMENT_COVER_BASIC_BLOCKS_H
 #define CPROVER_GOTO_INSTRUMENT_COVER_BASIC_BLOCKS_H
 
-#include <util/optional.h>
-
 #include <goto-programs/goto_program.h>
 
 #include "source_lines.h"
@@ -32,7 +30,7 @@ class cover_blocks_baset
   /// \param block_nr: a block number
   /// \return the instruction selected for
   ///   instrumentation representative of the given block
-  virtual optionalt<goto_programt::const_targett>
+  virtual std::optional<goto_programt::const_targett>
   instruction_of(std::size_t block_nr) const = 0;
 
   /// \param block_nr: a block number
@@ -77,7 +75,7 @@ class cover_basic_blockst final : public cover_blocks_baset
   /// \param block_nr: a block number
   /// \return the instruction selected for
   ///   instrumentation representative of the given block
-  optionalt<goto_programt::const_targett>
+  std::optional<goto_programt::const_targett>
   instruction_of(std::size_t block_nr) const override;
 
   /// \param block_nr: a block number
@@ -112,7 +110,7 @@ class cover_basic_blockst final : public cover_blocks_baset
   struct block_infot
   {
     /// the program location to instrument for this block
-    optionalt<goto_programt::const_targett> representative_inst;
+    std::optional<goto_programt::const_targett> representative_inst;
 
     /// the source location representative for this block
     /// (we need a separate copy of source locations because we attach
@@ -135,7 +133,7 @@ class cover_basic_blockst final : public cover_blocks_baset
 
   /// If this block is a continuation of a previous block through unconditional
   /// forward gotos, return this blocks number.
-  static optionalt<std::size_t> continuation_of_block(
+  static std::optional<std::size_t> continuation_of_block(
     const goto_programt::const_targett &instruction,
     block_mapt &block_map);
 };
@@ -161,7 +159,7 @@ class cover_basic_blocks_javat final : public cover_blocks_baset
 
   /// \param block_number: a block number
   /// \return first instruction of the given block
-  optionalt<goto_programt::const_targett>
+  std::optional<goto_programt::const_targett>
   instruction_of(std::size_t block_number) const override;
 
   /// \param block_number: a block number
diff --git a/src/goto-instrument/dump_c.cpp b/src/goto-instrument/dump_c.cpp
index 0b867faff8e..e1bc37c9509 100644
--- a/src/goto-instrument/dump_c.cpp
+++ b/src/goto-instrument/dump_c.cpp
@@ -728,7 +728,7 @@ void dump_ct::cleanup_decl(
   goto_programt tmp;
   tmp.add(goto_programt::make_decl(decl.symbol()));
 
-  if(optionalt<exprt> value = decl.initial_value())
+  if(std::optional<exprt> value = decl.initial_value())
   {
     decl.set_initial_value({});
     tmp.add(goto_programt::make_assignment(decl.symbol(), std::move(*value)));
@@ -1536,7 +1536,7 @@ void dump_ct::cleanup_expr(exprt &expr)
       }
     }
 
-    optionalt<exprt> clean_init;
+    std::optional<exprt> clean_init;
     if(
       ns.follow(bu.type()).id() == ID_union &&
       bu.source_location().get_function().empty())
diff --git a/src/goto-instrument/generate_function_bodies.cpp b/src/goto-instrument/generate_function_bodies.cpp
index 3687fb65187..be24ed70d30 100644
--- a/src/goto-instrument/generate_function_bodies.cpp
+++ b/src/goto-instrument/generate_function_bodies.cpp
@@ -355,8 +355,8 @@ class havoc_generate_function_bodiest : public generate_function_bodiest
 
 private:
   const std::vector<irep_idt> globals_to_havoc;
-  optionalt<std::regex> parameters_to_havoc;
-  optionalt<std::vector<std::size_t>> param_numbers_to_havoc;
+  std::optional<std::regex> parameters_to_havoc;
+  std::optional<std::vector<std::size_t>> param_numbers_to_havoc;
   const c_object_factory_parameterst &object_factory_parameters;
   mutable messaget message;
 };
diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp
index 55721374ce6..534294d484d 100644
--- a/src/goto-instrument/goto_instrument_parse_options.cpp
+++ b/src/goto-instrument/goto_instrument_parse_options.cpp
@@ -1214,8 +1214,8 @@ void goto_instrument_parse_optionst::instrument_goto_program()
       options,
       goto_model,
       harness_id,
-      to_enforce.empty() ? optionalt<irep_idt>{}
-                         : optionalt<irep_idt>{to_enforce.front()},
+      to_enforce.empty() ? std::optional<irep_idt>{}
+                         : std::optional<irep_idt>{to_enforce.front()},
       allow_recursive_calls,
       to_replace,
       cmdline.isset(FLAG_LOOP_CONTRACTS),
diff --git a/src/goto-instrument/unwindset.cpp b/src/goto-instrument/unwindset.cpp
index d15822489cb..7dc097efd03 100644
--- a/src/goto-instrument/unwindset.cpp
+++ b/src/goto-instrument/unwindset.cpp
@@ -33,7 +33,7 @@ void unwindsett::parse_unwindset_one_loop(
   if(val.empty())
     return;
 
-  optionalt<unsigned> thread_nr;
+  std::optional<unsigned> thread_nr;
   if(isdigit(val[0]))
   {
     auto c_pos = val.find(':');
@@ -116,8 +116,8 @@ void unwindsett::parse_unwindset_one_loop(
       }
       else
       {
-        optionalt<unsigned> nr;
-        optionalt<source_locationt> location;
+        std::optional<unsigned> nr;
+        std::optional<source_locationt> location;
         for(const auto &instruction : goto_function.body.instructions)
         {
           if(
@@ -161,7 +161,7 @@ void unwindsett::parse_unwindset_one_loop(
     std::string uw_string = val.substr(last_c_pos + 1);
 
     // the below initialisation makes g++-5 happy
-    optionalt<unsigned> uw(0);
+    std::optional<unsigned> uw(0);
 
     if(uw_string.empty())
       uw = {};
@@ -187,7 +187,7 @@ void unwindsett::parse_unwindset(
     parse_unwindset_one_loop(element, message_handler);
 }
 
-optionalt<unsigned>
+std::optional<unsigned>
 unwindsett::get_limit(const irep_idt &loop_id, unsigned thread_nr) const
 {
   // We use the most specific limit we have
diff --git a/src/goto-instrument/unwindset.h b/src/goto-instrument/unwindset.h
index b62ba11710e..4e3ffde0445 100644
--- a/src/goto-instrument/unwindset.h
+++ b/src/goto-instrument/unwindset.h
@@ -13,10 +13,10 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_GOTO_INSTRUMENT_UNWINDSET_H
 
 #include <util/irep.h>
-#include <util/optional.h>
 
 #include <list>
 #include <map>
+#include <optional>
 #include <string>
 
 class abstract_goto_modelt;
@@ -43,7 +43,8 @@ class unwindsett
     message_handlert &message_handler);
 
   // queries
-  optionalt<unsigned> get_limit(const irep_idt &loop, unsigned thread_id) const;
+  std::optional<unsigned>
+  get_limit(const irep_idt &loop, unsigned thread_id) const;
 
   // read unwindset directives from a file
   void parse_unwindset_file(
@@ -53,16 +54,16 @@ class unwindsett
 protected:
   abstract_goto_modelt &goto_model;
 
-  optionalt<unsigned> global_limit;
+  std::optional<unsigned> global_limit;
 
   // Limit for all instances of a loop.
   // This may have 'no value'.
-  typedef std::map<irep_idt, optionalt<unsigned>> loop_mapt;
+  typedef std::map<irep_idt, std::optional<unsigned>> loop_mapt;
   loop_mapt loop_map;
 
   // separate limits per thread
   using thread_loop_mapt =
-    std::map<std::pair<irep_idt, unsigned>, optionalt<unsigned>>;
+    std::map<std::pair<irep_idt, unsigned>, std::optional<unsigned>>;
   thread_loop_mapt thread_loop_map;
 
   void parse_unwindset_one_loop(
diff --git a/src/goto-programs/adjust_float_expressions.cpp b/src/goto-programs/adjust_float_expressions.cpp
index 9b44d90f1fe..eafea9ed5a3 100644
--- a/src/goto-programs/adjust_float_expressions.cpp
+++ b/src/goto-programs/adjust_float_expressions.cpp
@@ -207,7 +207,7 @@ void adjust_float_expressions(
   const namespacet &ns)
 {
   for(auto &i : goto_function.body.instructions)
-    i.transform([&ns](exprt expr) -> optionalt<exprt> {
+    i.transform([&ns](exprt expr) -> std::optional<exprt> {
       if(have_to_adjust_float_expressions(expr))
       {
         adjust_float_expressions(expr, ns);
diff --git a/src/goto-programs/destructor_tree.cpp b/src/goto-programs/destructor_tree.cpp
index e5452825555..224bb8fb334 100644
--- a/src/goto-programs/destructor_tree.cpp
+++ b/src/goto-programs/destructor_tree.cpp
@@ -16,7 +16,7 @@ void destructor_treet::add(const codet &destructor)
   current_node = new_node;
 }
 
-optionalt<codet> &destructor_treet::get_destructor(node_indext index)
+std::optional<codet> &destructor_treet::get_destructor(node_indext index)
 {
   PRECONDITION(index < destruction_graph.size());
   return destruction_graph[index].destructor_value;
@@ -54,8 +54,8 @@ const ancestry_resultt destructor_treet::get_nearest_common_ancestor_info(
 }
 
 const std::vector<destructor_and_idt> destructor_treet::get_destructors(
-  optionalt<node_indext> end_index,
-  optionalt<node_indext> starting_index)
+  std::optional<node_indext> end_index,
+  std::optional<node_indext> starting_index)
 {
   node_indext next_id = starting_index.value_or(get_current_node());
   node_indext end_id = end_index.value_or(0);
@@ -74,7 +74,7 @@ const std::vector<destructor_and_idt> destructor_treet::get_destructors(
   return codes;
 }
 
-void destructor_treet::set_current_node(optionalt<node_indext> val)
+void destructor_treet::set_current_node(std::optional<node_indext> val)
 {
   if(val)
     set_current_node(*val);
diff --git a/src/goto-programs/destructor_tree.h b/src/goto-programs/destructor_tree.h
index 286e5678f82..719f308babb 100644
--- a/src/goto-programs/destructor_tree.h
+++ b/src/goto-programs/destructor_tree.h
@@ -99,7 +99,7 @@ class destructor_treet
   void add(const codet &destructor);
 
   /// Fetches the destructor value for the passed-in node index.
-  optionalt<codet> &get_destructor(node_indext index);
+  std::optional<codet> &get_destructor(node_indext index);
 
   /// Builds a vector of destructors that start from starting_index and ends
   /// at end_index.
@@ -110,8 +110,8 @@ class destructor_treet
   /// \return collection of destructors that should be called for the
   ///     range supplied.
   const std::vector<destructor_and_idt> get_destructors(
-    optionalt<node_indext> end_index = {},
-    optionalt<node_indext> starting_index = {});
+    std::optional<node_indext> end_index = {},
+    std::optional<node_indext> starting_index = {});
 
   /// Finds the nearest common ancestor of two nodes and then returns it.
   /// This should be used when you want to find out what parts of the two
@@ -123,7 +123,7 @@ class destructor_treet
   /// Sets the current node. Next time a node is added to the stack it will
   /// be added as a child of this node. If passed an empty index, no
   /// assignment will be done.
-  void set_current_node(optionalt<node_indext> val);
+  void set_current_node(std::optional<node_indext> val);
 
   /// Sets the current node. Next time a node is added to the stack it will
   /// be added as a child of this node.
@@ -145,7 +145,7 @@ class destructor_treet
       : destructor_value(std::move(destructor))
     {
     }
-    optionalt<codet> destructor_value;
+    std::optional<codet> destructor_value;
   };
 
   grapht<destructor_nodet> destruction_graph;
diff --git a/src/goto-programs/format_strings.cpp b/src/goto-programs/format_strings.cpp
index 831a1bc8cf7..ecbf78e5fe5 100644
--- a/src/goto-programs/format_strings.cpp
+++ b/src/goto-programs/format_strings.cpp
@@ -225,7 +225,7 @@ format_token_listt parse_format_string(const std::string &arg_string)
   return token_list;
 }
 
-optionalt<typet> get_type(const format_tokent &token)
+std::optional<typet> get_type(const format_tokent &token)
 {
   switch(token.type)
   {
diff --git a/src/goto-programs/format_strings.h b/src/goto-programs/format_strings.h
index 82e548d74cf..7e77c032cae 100644
--- a/src/goto-programs/format_strings.h
+++ b/src/goto-programs/format_strings.h
@@ -12,12 +12,12 @@ Author: CM Wintersteiger
 #ifndef CPROVER_GOTO_PROGRAMS_FORMAT_STRINGS_H
 #define CPROVER_GOTO_PROGRAMS_FORMAT_STRINGS_H
 
-#include <string>
-#include <list>
-
 #include <util/irep.h>
 #include <util/mp_arith.h>
-#include <util/optional.h>
+
+#include <list>
+#include <optional>
+#include <string>
 
 class typet;
 
@@ -91,6 +91,6 @@ typedef std::list<format_tokent> format_token_listt;
 
 format_token_listt parse_format_string(const std::string &);
 
-optionalt<typet> get_type(const format_tokent &);
+std::optional<typet> get_type(const format_tokent &);
 
 #endif // CPROVER_GOTO_PROGRAMS_FORMAT_STRINGS_H
diff --git a/src/goto-programs/goto_convert_class.h b/src/goto-programs/goto_convert_class.h
index 05bc4aae991..84a48ae06a1 100644
--- a/src/goto-programs/goto_convert_class.h
+++ b/src/goto-programs/goto_convert_class.h
@@ -359,8 +359,8 @@ class goto_convertt:public messaget
     const source_locationt &source_location,
     goto_programt &dest,
     const irep_idt &mode,
-    optionalt<node_indext> destructor_start_point = {},
-    optionalt<node_indext> destructor_end_point = {});
+    std::optional<node_indext> destructor_start_point = {},
+    std::optional<node_indext> destructor_end_point = {});
 
   //
   // gotos
diff --git a/src/goto-programs/goto_convert_exceptions.cpp b/src/goto-programs/goto_convert_exceptions.cpp
index f6b0a7a3608..7bb21ac2b61 100644
--- a/src/goto-programs/goto_convert_exceptions.cpp
+++ b/src/goto-programs/goto_convert_exceptions.cpp
@@ -281,8 +281,8 @@ void goto_convertt::unwind_destructor_stack(
   const source_locationt &source_location,
   goto_programt &dest,
   const irep_idt &mode,
-  optionalt<node_indext> end_index,
-  optionalt<node_indext> starting_index)
+  std::optional<node_indext> end_index,
+  std::optional<node_indext> starting_index)
 {
   // As we go we'll keep targets.destructor_stack.current_node pointing at the
   // next node we intend to destroy, so that if our convert(...) call for each
@@ -305,7 +305,7 @@ void goto_convertt::unwind_destructor_stack(
   {
     node_indext current_node = targets.destructor_stack.get_current_node();
 
-    optionalt<codet> &destructor =
+    std::optional<codet> &destructor =
       targets.destructor_stack.get_destructor(current_node);
 
     // Descend the tree before unwinding so we don't re-do the current node
diff --git a/src/goto-programs/goto_convert_side_effect.cpp b/src/goto-programs/goto_convert_side_effect.cpp
index 7cb9837c06e..f7ff84f02d4 100644
--- a/src/goto-programs/goto_convert_side_effect.cpp
+++ b/src/goto-programs/goto_convert_side_effect.cpp
@@ -46,7 +46,7 @@ void goto_convertt::remove_assignment(
 {
   const irep_idt statement=expr.get_statement();
 
-  optionalt<exprt> replacement_expr_opt;
+  std::optional<exprt> replacement_expr_opt;
 
   if(statement==ID_assign)
   {
diff --git a/src/goto-programs/goto_instruction_code.cpp b/src/goto-programs/goto_instruction_code.cpp
index 1547364f1a7..65826ee8b7e 100644
--- a/src/goto-programs/goto_instruction_code.cpp
+++ b/src/goto-programs/goto_instruction_code.cpp
@@ -21,7 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com
 
 code_inputt::code_inputt(
   std::vector<exprt> arguments,
-  optionalt<source_locationt> location)
+  std::optional<source_locationt> location)
   : codet{ID_input, std::move(arguments)}
 {
   if(location)
@@ -32,12 +32,13 @@ code_inputt::code_inputt(
 code_inputt::code_inputt(
   const irep_idt &description,
   exprt expression,
-  optionalt<source_locationt> location)
-  : code_inputt{{address_of_exprt(index_exprt(
-                   string_constantt(description),
-                   from_integer(0, c_index_type()))),
-                 std::move(expression)},
-                std::move(location)}
+  std::optional<source_locationt> location)
+  : code_inputt{
+      {address_of_exprt(index_exprt(
+         string_constantt(description),
+         from_integer(0, c_index_type()))),
+       std::move(expression)},
+      std::move(location)}
 {
 }
 
@@ -49,7 +50,7 @@ void code_inputt::check(const codet &code, const validation_modet vm)
 
 code_outputt::code_outputt(
   std::vector<exprt> arguments,
-  optionalt<source_locationt> location)
+  std::optional<source_locationt> location)
   : codet{ID_output, std::move(arguments)}
 {
   if(location)
@@ -60,12 +61,13 @@ code_outputt::code_outputt(
 code_outputt::code_outputt(
   const irep_idt &description,
   exprt expression,
-  optionalt<source_locationt> location)
-  : code_outputt{{address_of_exprt(index_exprt(
-                    string_constantt(description),
-                    from_integer(0, c_index_type()))),
-                  std::move(expression)},
-                 std::move(location)}
+  std::optional<source_locationt> location)
+  : code_outputt{
+      {address_of_exprt(index_exprt(
+         string_constantt(description),
+         from_integer(0, c_index_type()))),
+       std::move(expression)},
+      std::move(location)}
 {
 }
 
diff --git a/src/goto-programs/goto_instruction_code.h b/src/goto-programs/goto_instruction_code.h
index a7d53e67850..946cbe61119 100644
--- a/src/goto-programs/goto_instruction_code.h
+++ b/src/goto-programs/goto_instruction_code.h
@@ -411,7 +411,7 @@ class code_inputt : public goto_instruction_codet
   /// `const char *` and one or more corresponding expression arguments follow.
   explicit code_inputt(
     std::vector<exprt> arguments,
-    optionalt<source_locationt> location = {});
+    std::optional<source_locationt> location = {});
 
   /// This constructor is intended for generating input instructions as part of
   /// synthetic entry point code, rather than as part of user code.
@@ -424,7 +424,7 @@ class code_inputt : public goto_instruction_codet
   code_inputt(
     const irep_idt &description,
     exprt expression,
-    optionalt<source_locationt> location = {});
+    std::optional<source_locationt> location = {});
 
   static void check(
     const goto_instruction_codet &code,
@@ -458,7 +458,7 @@ class code_outputt : public goto_instruction_codet
   /// `const char *` and one or more corresponding expression arguments follow.
   explicit code_outputt(
     std::vector<exprt> arguments,
-    optionalt<source_locationt> location = {});
+    std::optional<source_locationt> location = {});
 
   /// This constructor is intended for generating output instructions as part of
   /// synthetic entry point code, rather than as part of user code.
@@ -470,7 +470,7 @@ class code_outputt : public goto_instruction_codet
   code_outputt(
     const irep_idt &description,
     exprt expression,
-    optionalt<source_locationt> location = {});
+    std::optional<source_locationt> location = {});
 
   static void check(
     const goto_instruction_codet &code,
diff --git a/src/goto-programs/goto_program.cpp b/src/goto-programs/goto_program.cpp
index f80328a5722..db89fd0f4fd 100644
--- a/src/goto-programs/goto_program.cpp
+++ b/src/goto-programs/goto_program.cpp
@@ -982,7 +982,7 @@ void goto_programt::instructiont::validate(
 }
 
 void goto_programt::instructiont::transform(
-  std::function<optionalt<exprt>(exprt)> f)
+  std::function<std::optional<exprt>(exprt)> f)
 {
   switch(_type)
   {
diff --git a/src/goto-programs/goto_program.h b/src/goto-programs/goto_program.h
index 8d17e400e25..5cbe7fc9ac2 100644
--- a/src/goto-programs/goto_program.h
+++ b/src/goto-programs/goto_program.h
@@ -598,7 +598,7 @@ class goto_programt
 
     /// Apply given transformer to all expressions; no return value
     /// means no change needed.
-    void transform(std::function<optionalt<exprt>(exprt)>);
+    void transform(std::function<std::optional<exprt>(exprt)>);
 
     /// Apply given function to all expressions
     void apply(std::function<void(const exprt &)>) const;
diff --git a/src/goto-programs/goto_trace.cpp b/src/goto-programs/goto_trace.cpp
index ed2c4a401e1..1c1f1625028 100644
--- a/src/goto-programs/goto_trace.cpp
+++ b/src/goto-programs/goto_trace.cpp
@@ -30,7 +30,7 @@ Author: Daniel Kroening
 
 #include <ostream>
 
-static optionalt<symbol_exprt> get_object_rec(const exprt &src)
+static std::optional<symbol_exprt> get_object_rec(const exprt &src)
 {
   if(src.id()==ID_symbol)
     return to_symbol_expr(src);
@@ -50,7 +50,7 @@ static optionalt<symbol_exprt> get_object_rec(const exprt &src)
     return {}; // give up
 }
 
-optionalt<symbol_exprt> goto_trace_stept::get_lhs_object() const
+std::optional<symbol_exprt> goto_trace_stept::get_lhs_object() const
 {
   return get_object_rec(full_lhs);
 }
@@ -292,7 +292,7 @@ std::string trace_numeric_value(
 static void trace_value(
   messaget::mstreamt &out,
   const namespacet &ns,
-  const optionalt<symbol_exprt> &lhs_object,
+  const std::optional<symbol_exprt> &lhs_object,
   const exprt &full_lhs,
   const exprt &value,
   const trace_optionst &options)
diff --git a/src/goto-programs/goto_trace.h b/src/goto-programs/goto_trace.h
index e6b6ea727a7..a9c91cf98e1 100644
--- a/src/goto-programs/goto_trace.h
+++ b/src/goto-programs/goto_trace.h
@@ -127,7 +127,7 @@ class goto_trace_stept
   exprt full_lhs;
 
   // the object being assigned
-  optionalt<symbol_exprt> get_lhs_object() const;
+  std::optional<symbol_exprt> get_lhs_object() const;
 
   // A constant with the new value of the lhs
   exprt full_lhs_value;
diff --git a/src/goto-programs/interpreter_class.h b/src/goto-programs/interpreter_class.h
index 425934e87fa..e873546db7a 100644
--- a/src/goto-programs/interpreter_class.h
+++ b/src/goto-programs/interpreter_class.h
@@ -107,7 +107,7 @@ class interpretert
   const goto_functionst &goto_functions;
 
   typedef std::unordered_map<irep_idt, mp_integer> memory_mapt;
-  using inverse_memory_mapt = std::map<mp_integer, optionalt<symbol_exprt>>;
+  using inverse_memory_mapt = std::map<mp_integer, std::optional<symbol_exprt>>;
   memory_mapt memory_map;
   inverse_memory_mapt inverse_memory_map;
 
diff --git a/src/goto-programs/link_goto_model.cpp b/src/goto-programs/link_goto_model.cpp
index 5c66ae0d6ef..81ea5b3edda 100644
--- a/src/goto-programs/link_goto_model.cpp
+++ b/src/goto-programs/link_goto_model.cpp
@@ -106,7 +106,7 @@ static bool link_functions(
   return false;
 }
 
-optionalt<replace_symbolt::expr_mapt> link_goto_model(
+std::optional<replace_symbolt::expr_mapt> link_goto_model(
   goto_modelt &dest,
   goto_modelt &&src,
   message_handlert &message_handler)
@@ -217,7 +217,7 @@ void finalize_linking(
         {
           instruction.transform([&object_type_updates](exprt expr) {
             const bool changed = !object_type_updates.replace(expr);
-            return changed ? optionalt<exprt>{expr} : std::nullopt;
+            return changed ? std::optional<exprt>{expr} : std::nullopt;
           });
         }
       }
diff --git a/src/goto-programs/link_goto_model.h b/src/goto-programs/link_goto_model.h
index cf37cfe4dba..04ba2cacdf2 100644
--- a/src/goto-programs/link_goto_model.h
+++ b/src/goto-programs/link_goto_model.h
@@ -22,7 +22,7 @@ class message_handlert;
 /// which need to be applied using \ref finalize_linking.
 /// \return nullopt if linking fails, else a (possibly empty) collection of
 ///   replacements to be applied.
-[[nodiscard]] optionalt<replace_symbolt::expr_mapt>
+[[nodiscard]] std::optional<replace_symbolt::expr_mapt>
 link_goto_model(goto_modelt &dest, goto_modelt &&src, message_handlert &);
 
 /// Apply \p type_updates to \p dest, where \p type_updates were constructed
diff --git a/src/goto-programs/link_to_library.cpp b/src/goto-programs/link_to_library.cpp
index ed26d11a85b..f3743320920 100644
--- a/src/goto-programs/link_to_library.cpp
+++ b/src/goto-programs/link_to_library.cpp
@@ -19,7 +19,8 @@ Author: Daniel Kroening, kroening@kroening.com
 #include "link_goto_model.h"
 
 /// Try to add \p missing_function from \p library to \p goto_model.
-static std::pair<optionalt<replace_symbolt::expr_mapt>, bool> add_one_function(
+static std::pair<std::optional<replace_symbolt::expr_mapt>, bool>
+add_one_function(
   goto_modelt &goto_model,
   message_handlert &message_handler,
   const std::function<void(
diff --git a/src/goto-programs/read_goto_binary.cpp b/src/goto-programs/read_goto_binary.cpp
index 73665d1ccb3..89b07a92a99 100644
--- a/src/goto-programs/read_goto_binary.cpp
+++ b/src/goto-programs/read_goto_binary.cpp
@@ -35,7 +35,7 @@ static bool read_goto_binary(
 /// \param filename: the file name of the goto binary
 /// \param message_handler: for diagnostics
 /// \return goto model on success, {} on failure
-optionalt<goto_modelt>
+std::optional<goto_modelt>
 read_goto_binary(const std::string &filename, message_handlert &message_handler)
 {
   goto_modelt dest;
@@ -261,7 +261,7 @@ bool is_goto_binary(
 /// \param dest: the goto model returned
 /// \param message_handler: for diagnostics
 /// \return nullopt on error, type replacements to be applied otherwise
-static optionalt<replace_symbolt::expr_mapt> read_object_and_link(
+static std::optional<replace_symbolt::expr_mapt> read_object_and_link(
   const std::string &file_name,
   goto_modelt &dest,
   message_handlert &message_handler)
diff --git a/src/goto-programs/read_goto_binary.h b/src/goto-programs/read_goto_binary.h
index 462657df8b6..58934b2bc71 100644
--- a/src/goto-programs/read_goto_binary.h
+++ b/src/goto-programs/read_goto_binary.h
@@ -13,14 +13,13 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_GOTO_PROGRAMS_READ_GOTO_BINARY_H
 
 #include <list>
+#include <optional>
 #include <string>
 
-#include <util/optional.h>
-
 class goto_modelt;
 class message_handlert;
 
-optionalt<goto_modelt>
+std::optional<goto_modelt>
 read_goto_binary(const std::string &filename, message_handlert &);
 
 bool is_goto_binary(const std::string &filename, message_handlert &);
diff --git a/src/goto-programs/remove_complex.cpp b/src/goto-programs/remove_complex.cpp
index c13ad86bab4..c983692cfb1 100644
--- a/src/goto-programs/remove_complex.cpp
+++ b/src/goto-programs/remove_complex.cpp
@@ -286,7 +286,7 @@ static void remove_complex(
   goto_functionst::goto_functiont &goto_function)
 {
   for(auto &i : goto_function.body.instructions)
-    i.transform([](exprt e) -> optionalt<exprt> {
+    i.transform([](exprt e) -> std::optional<exprt> {
       if(have_to_remove_complex(e))
       {
         remove_complex(e);
diff --git a/src/goto-programs/remove_returns.cpp b/src/goto-programs/remove_returns.cpp
index 2c9248965b7..f92f07358aa 100644
--- a/src/goto-programs/remove_returns.cpp
+++ b/src/goto-programs/remove_returns.cpp
@@ -59,11 +59,11 @@ class remove_returnst
   void undo_function_calls(
     goto_programt &goto_program);
 
-  optionalt<symbol_exprt>
+  std::optional<symbol_exprt>
   get_or_create_return_value_symbol(const irep_idt &function_id);
 };
 
-optionalt<symbol_exprt>
+std::optional<symbol_exprt>
 remove_returnst::get_or_create_return_value_symbol(const irep_idt &function_id)
 {
   const namespacet ns(symbol_table);
@@ -173,7 +173,7 @@ bool remove_returnst::do_function_calls(
         exprt rhs;
 
         bool is_stub = function_is_stub(function_id);
-        optionalt<symbol_exprt> return_value;
+        std::optional<symbol_exprt> return_value;
 
         if(!is_stub)
           return_value = get_or_create_return_value_symbol(function_id);
diff --git a/src/goto-programs/remove_vector.cpp b/src/goto-programs/remove_vector.cpp
index 32f589e99e3..2809f8cfa1c 100644
--- a/src/goto-programs/remove_vector.cpp
+++ b/src/goto-programs/remove_vector.cpp
@@ -354,7 +354,7 @@ static void remove_vector(symbol_table_baset &symbol_table)
 void remove_vector(goto_functionst::goto_functiont &goto_function)
 {
   for(auto &i : goto_function.body.instructions)
-    i.transform([](exprt e) -> optionalt<exprt> {
+    i.transform([](exprt e) -> std::optional<exprt> {
       if(have_to_remove_vector(e))
       {
         remove_vector(e);
diff --git a/src/goto-programs/remove_virtual_functions.cpp b/src/goto-programs/remove_virtual_functions.cpp
index 171a0037774..08eb51fe640 100644
--- a/src/goto-programs/remove_virtual_functions.cpp
+++ b/src/goto-programs/remove_virtual_functions.cpp
@@ -45,13 +45,13 @@ class get_virtual_calleest
   const class_hierarchyt &class_hierarchy;
 
   typedef std::function<
-    optionalt<resolve_inherited_componentt::inherited_componentt>(
+    std::optional<resolve_inherited_componentt::inherited_componentt>(
       const irep_idt &,
       const irep_idt &)>
     function_call_resolvert;
   void get_child_functions_rec(
     const irep_idt &,
-    const optionalt<symbol_exprt> &,
+    const std::optional<symbol_exprt> &,
     const irep_idt &,
     dispatch_table_entriest &,
     dispatch_table_entries_mapt &) const;
@@ -507,7 +507,7 @@ goto_programt::targett remove_virtual_functionst::remove_virtual_function(
 /// \param entry_map: map of class identifiers to dispatch table entries
 void get_virtual_calleest::get_child_functions_rec(
   const irep_idt &this_id,
-  const optionalt<symbol_exprt> &last_method_defn,
+  const std::optional<symbol_exprt> &last_method_defn,
   const irep_idt &component_name,
   dispatch_table_entriest &functions,
   dispatch_table_entries_mapt &entry_map) const
diff --git a/src/goto-programs/remove_virtual_functions.h b/src/goto-programs/remove_virtual_functions.h
index 394db351c98..5dd9d7d1e51 100644
--- a/src/goto-programs/remove_virtual_functions.h
+++ b/src/goto-programs/remove_virtual_functions.h
@@ -15,7 +15,6 @@ Date: April 2016
 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_VIRTUAL_FUNCTIONS_H
 #define CPROVER_GOTO_PROGRAMS_REMOVE_VIRTUAL_FUNCTIONS_H
 
-#include <util/optional.h>
 #include <util/std_expr.h>
 
 #include "goto_program.h"
@@ -96,7 +95,7 @@ class dispatch_table_entryt
   }
 #endif
 
-  optionalt<symbol_exprt> symbol_expr;
+  std::optional<symbol_exprt> symbol_expr;
   irep_idt class_id;
 };
 
diff --git a/src/goto-programs/resolve_inherited_component.cpp b/src/goto-programs/resolve_inherited_component.cpp
index 4a264460685..d3d855bbeff 100644
--- a/src/goto-programs/resolve_inherited_component.cpp
+++ b/src/goto-programs/resolve_inherited_component.cpp
@@ -32,7 +32,7 @@ resolve_inherited_componentt::resolve_inherited_componentt(
 /// \param user_filter: Predicate that should return true for symbols that can
 ///   be returned. Those for which it returns false will be ignored.
 /// \return The concrete component that has been resolved
-optionalt<resolve_inherited_componentt::inherited_componentt>
+std::optional<resolve_inherited_componentt::inherited_componentt>
 resolve_inherited_componentt::operator()(
   const irep_idt &class_id,
   const irep_idt &component_name,
@@ -122,7 +122,7 @@ irep_idt resolve_inherited_componentt::inherited_componentt::
 ///   class specifier)
 /// \param symbol_table: Global symbol table
 /// \return The concrete component that has been resolved
-optionalt<resolve_inherited_componentt::inherited_componentt>
+std::optional<resolve_inherited_componentt::inherited_componentt>
 get_inherited_method_implementation(
   const irep_idt &call_basename,
   const irep_idt &classname,
diff --git a/src/goto-programs/resolve_inherited_component.h b/src/goto-programs/resolve_inherited_component.h
index 26210b59aff..a15d61c68e5 100644
--- a/src/goto-programs/resolve_inherited_component.h
+++ b/src/goto-programs/resolve_inherited_component.h
@@ -14,9 +14,9 @@ Author: Diffblue Ltd.
 #define CPROVER_GOTO_PROGRAMS_RESOLVE_INHERITED_COMPONENT_H
 
 #include <util/irep.h>
-#include <util/optional.h>
 
 #include <functional>
+#include <optional>
 
 class symbolt;
 class symbol_table_baset;
@@ -47,7 +47,7 @@ class resolve_inherited_componentt
     irep_idt component_identifier;
   };
 
-  optionalt<inherited_componentt> operator()(
+  std::optional<inherited_componentt> operator()(
     const irep_idt &class_id,
     const irep_idt &component_name,
     bool include_interfaces,
@@ -62,7 +62,7 @@ class resolve_inherited_componentt
   const symbol_table_baset &symbol_table;
 };
 
-optionalt<resolve_inherited_componentt::inherited_componentt>
+std::optional<resolve_inherited_componentt::inherited_componentt>
 get_inherited_method_implementation(
   const irep_idt &call_basename,
   const irep_idt &classname,
diff --git a/src/goto-programs/restrict_function_pointers.cpp b/src/goto-programs/restrict_function_pointers.cpp
index 1fa3c6f94be..e7ddab4fa06 100644
--- a/src/goto-programs/restrict_function_pointers.cpp
+++ b/src/goto-programs/restrict_function_pointers.cpp
@@ -323,7 +323,7 @@ static std::string resolve_pointer_name(
   const auto it = goto_model.goto_functions.function_map.find(function_id);
   if(it != goto_model.goto_functions.function_map.end())
   {
-    optionalt<source_locationt> location;
+    std::optional<source_locationt> location;
     for(const auto &instruction : it->second.body.instructions)
     {
       if(
@@ -421,7 +421,7 @@ function_pointer_restrictionst::parse_function_pointer_restriction(
   return std::make_pair(pointer_name, target_names);
 }
 
-optionalt<function_pointer_restrictionst::restrictiont>
+std::optional<function_pointer_restrictionst::restrictiont>
 function_pointer_restrictionst::get_by_name_restriction(
   const goto_functiont &goto_function,
   const function_pointer_restrictionst::restrictionst &by_name_restrictions,
@@ -457,7 +457,7 @@ function_pointer_restrictionst::get_by_name_restriction(
 
   if(restriction != by_name_restrictions.end())
   {
-    return optionalt<function_pointer_restrictionst::restrictiont>(
+    return std::optional<function_pointer_restrictionst::restrictiont>(
       std::make_pair(
         function_pointer_call_site.get_identifier(), restriction->second));
   }
diff --git a/src/goto-programs/restrict_function_pointers.h b/src/goto-programs/restrict_function_pointers.h
index 1046a6b9737..b934db7d6d7 100644
--- a/src/goto-programs/restrict_function_pointers.h
+++ b/src/goto-programs/restrict_function_pointers.h
@@ -22,7 +22,6 @@ Author: Diffblue Ltd.
 
 #include <util/exception_utils.h>
 #include <util/irep.h>
-#include <util/optional.h>
 
 #include "goto_program.h"
 
@@ -132,7 +131,7 @@ class function_pointer_restrictionst
     const std::string &option,
     const goto_modelt &goto_model);
 
-  static optionalt<restrictiont> get_by_name_restriction(
+  static std::optional<restrictiont> get_by_name_restriction(
     const goto_functiont &goto_function,
     const function_pointer_restrictionst::restrictionst &by_name_restrictions,
     const goto_programt::const_targett &location);
diff --git a/src/goto-programs/rewrite_rw_ok.cpp b/src/goto-programs/rewrite_rw_ok.cpp
index 09433e5d8df..b23c7616402 100644
--- a/src/goto-programs/rewrite_rw_ok.cpp
+++ b/src/goto-programs/rewrite_rw_ok.cpp
@@ -13,7 +13,7 @@ Author: Michael Tautschnig
 
 #include <goto-programs/goto_model.h>
 
-static optionalt<exprt> rewrite_rw_ok(exprt expr, const namespacet &ns)
+static std::optional<exprt> rewrite_rw_ok(exprt expr, const namespacet &ns)
 {
   bool unchanged = true;
 
diff --git a/src/goto-programs/rewrite_union.cpp b/src/goto-programs/rewrite_union.cpp
index f52dfe04f9f..3fcb4b33e91 100644
--- a/src/goto-programs/rewrite_union.cpp
+++ b/src/goto-programs/rewrite_union.cpp
@@ -152,7 +152,7 @@ static bool restore_union_rec(exprt &expr, const namespacet &ns)
           comp.type().id() == ID_array || comp.type().id() == ID_struct ||
           comp.type().id() == ID_struct_tag)
         {
-          optionalt<exprt> result = get_subexpression_at_offset(
+          std::optional<exprt> result = get_subexpression_at_offset(
             member_exprt{be.op(), comp.get_name(), comp.type()},
             be.offset(),
             be.type(),
diff --git a/src/goto-programs/show_properties.cpp b/src/goto-programs/show_properties.cpp
index 90be11961c2..c3e94c26600 100644
--- a/src/goto-programs/show_properties.cpp
+++ b/src/goto-programs/show_properties.cpp
@@ -19,9 +19,8 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include "goto_model.h"
 
-optionalt<source_locationt> find_property(
-    const irep_idt &property,
-    const goto_functionst & goto_functions)
+std::optional<source_locationt>
+find_property(const irep_idt &property, const goto_functionst &goto_functions)
 {
   for(const auto &fct : goto_functions.function_map)
   {
diff --git a/src/goto-programs/show_properties.h b/src/goto-programs/show_properties.h
index 0e41f5c85d1..1a7cfa494ca 100644
--- a/src/goto-programs/show_properties.h
+++ b/src/goto-programs/show_properties.h
@@ -13,7 +13,8 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_GOTO_PROGRAMS_SHOW_PROPERTIES_H
 
 #include <util/irep.h>
-#include <util/optional.h>
+
+#include <optional>
 
 class json_arrayt;
 class namespacet;
@@ -45,9 +46,8 @@ void show_properties(
 ///   the property
 /// \return optional<source_locationt> the location of the
 ///   property, if found.
-optionalt<source_locationt> find_property(
-    const irep_idt &property,
-    const goto_functionst &goto_functions);
+std::optional<source_locationt>
+find_property(const irep_idt &property, const goto_functionst &goto_functions);
 
 /// \brief Collects the properties in the goto program into a `json_arrayt`
 /// \param json_properties: JSON array to hold the properties
diff --git a/src/goto-programs/structured_trace_util.cpp b/src/goto-programs/structured_trace_util.cpp
index 07260626a9b..d547f153853 100644
--- a/src/goto-programs/structured_trace_util.cpp
+++ b/src/goto-programs/structured_trace_util.cpp
@@ -36,7 +36,7 @@ std::string default_step_name(const default_step_kindt &step_type)
   UNREACHABLE;
 }
 
-optionalt<default_trace_stept> default_step(
+std::optional<default_trace_stept> default_step(
   const goto_trace_stept &step,
   const source_locationt &previous_source_location)
 {
diff --git a/src/goto-programs/structured_trace_util.h b/src/goto-programs/structured_trace_util.h
index e8bbbf32b16..bd48aec9702 100644
--- a/src/goto-programs/structured_trace_util.h
+++ b/src/goto-programs/structured_trace_util.h
@@ -46,7 +46,7 @@ struct default_trace_stept
   source_locationt location;
 };
 
-optionalt<default_trace_stept> default_step(
+std::optional<default_trace_stept> default_step(
   const goto_trace_stept &step,
   const source_locationt &previous_source_location);
 
diff --git a/src/goto-symex/frame.h b/src/goto-symex/frame.h
index e5edcf4acb7..cd10b391b62 100644
--- a/src/goto-symex/frame.h
+++ b/src/goto-symex/frame.h
@@ -36,7 +36,7 @@ struct framet
   guardt guard_at_function_start;
   goto_programt::const_targett end_of_function;
   exprt call_lhs = nil_exprt();                // cleaned, but not renamed
-  optionalt<symbol_exprt> return_value_symbol; // not renamed
+  std::optional<symbol_exprt> return_value_symbol; // not renamed
   bool hidden_function = false;
 
   symex_level1t old_level1;
diff --git a/src/goto-symex/goto_symex.cpp b/src/goto-symex/goto_symex.cpp
index 9fff87a639d..f2c88ae4b1b 100644
--- a/src/goto-symex/goto_symex.cpp
+++ b/src/goto-symex/goto_symex.cpp
@@ -362,7 +362,7 @@ void goto_symext::associate_array_to_pointer(
     ssa_expr, expr_skeletont{}, array_to_pointer_app, {});
 }
 
-optionalt<std::reference_wrapper<const array_exprt>>
+std::optional<std::reference_wrapper<const array_exprt>>
 goto_symext::try_evaluate_constant_string(
   const statet &state,
   const exprt &content)
@@ -383,7 +383,7 @@ goto_symext::try_evaluate_constant_string(
   return try_get_string_data_array(s_pointer_opt->get(), ns);
 }
 
-optionalt<std::reference_wrapper<const constant_exprt>>
+std::optional<std::reference_wrapper<const constant_exprt>>
 goto_symext::try_evaluate_constant(const statet &state, const exprt &expr)
 {
   if(expr.id() != ID_symbol)
@@ -399,7 +399,7 @@ goto_symext::try_evaluate_constant(const statet &state, const exprt &expr)
     return {};
   }
 
-  return optionalt<std::reference_wrapper<const constant_exprt>>(
+  return std::optional<std::reference_wrapper<const constant_exprt>>(
     to_constant_expr(constant_expr_opt->get()));
 }
 
diff --git a/src/goto-symex/goto_symex.h b/src/goto-symex/goto_symex.h
index 72de8769922..85b2622aed8 100644
--- a/src/goto-symex/goto_symex.h
+++ b/src/goto-symex/goto_symex.h
@@ -742,11 +742,11 @@ class goto_symext
     const array_exprt &new_char_array,
     const address_of_exprt &string_data);
 
-  optionalt<std::reference_wrapper<const array_exprt>>
+  std::optional<std::reference_wrapper<const array_exprt>>
   try_evaluate_constant_string(const statet &state, const exprt &content);
 
   // clang-format off
-  static optionalt<std::reference_wrapper<const constant_exprt>>
+  static std::optional<std::reference_wrapper<const constant_exprt>>
   try_evaluate_constant(
     const statet &state,
     const exprt &expr);
diff --git a/src/goto-symex/renamed.h b/src/goto-symex/renamed.h
index 1f6da139f13..71bf60403e9 100644
--- a/src/goto-symex/renamed.h
+++ b/src/goto-symex/renamed.h
@@ -48,7 +48,7 @@ class renamedt : private underlyingt
   }
 
   using mutator_functiont =
-    std::function<optionalt<renamedt>(const renamedt &)>;
+    std::function<std::optional<renamedt>(const renamedt &)>;
 
 private:
   underlyingt &value()
@@ -99,7 +99,7 @@ void selectively_mutate(
   for(auto it = renamed.depth_begin(), itend = renamed.depth_end(); it != itend;
       ++it)
   {
-    optionalt<renamedt<exprt, level>> replacement =
+    std::optional<renamedt<exprt, level>> replacement =
       get_mutated_expr(static_cast<const renamedt<exprt, level> &>(*it));
 
     if(replacement)
diff --git a/src/goto-symex/renaming_level.cpp b/src/goto-symex/renaming_level.cpp
index cb77b6610e3..7109f4b0c09 100644
--- a/src/goto-symex/renaming_level.cpp
+++ b/src/goto-symex/renaming_level.cpp
@@ -52,7 +52,8 @@ void symex_level1t::insert(
     ssa.get().get_identifier(), std::make_pair(ssa.get(), index));
 }
 
-optionalt<std::pair<ssa_exprt, std::size_t>> symex_level1t::insert_or_replace(
+std::optional<std::pair<ssa_exprt, std::size_t>>
+symex_level1t::insert_or_replace(
   const renamedt<ssa_exprt, L0> &ssa,
   std::size_t index)
 {
diff --git a/src/goto-symex/renaming_level.h b/src/goto-symex/renaming_level.h
index 211b3fc3b86..eda7865f59a 100644
--- a/src/goto-symex/renaming_level.h
+++ b/src/goto-symex/renaming_level.h
@@ -44,7 +44,7 @@ struct symex_level1t
   /// Set the index for \p ssa to index.
   /// \return if an index for \p ssa was already know, returns it's previous
   ///   value.
-  optionalt<std::pair<ssa_exprt, std::size_t>>
+  std::optional<std::pair<ssa_exprt, std::size_t>>
   insert_or_replace(const renamedt<ssa_exprt, L0> &ssa, std::size_t index);
 
   /// \return true if \p ssa has an associated index
diff --git a/src/goto-symex/shadow_memory.cpp b/src/goto-symex/shadow_memory.cpp
index b8481c7c02d..43dbf4aa899 100644
--- a/src/goto-symex/shadow_memory.cpp
+++ b/src/goto-symex/shadow_memory.cpp
@@ -126,7 +126,7 @@ void shadow_memoryt::symex_set_field(
   // build lhs
   const exprt &rhs = value;
   size_t mux_size = 0;
-  optionalt<exprt> maybe_lhs =
+  std::optional<exprt> maybe_lhs =
     get_shadow_memory(expr, value_set, addresses, ns, log, mux_size);
 
   // add to equation
diff --git a/src/goto-symex/shadow_memory_util.cpp b/src/goto-symex/shadow_memory_util.cpp
index b33920b258b..32aa569e307 100644
--- a/src/goto-symex/shadow_memory_util.cpp
+++ b/src/goto-symex/shadow_memory_util.cpp
@@ -1127,7 +1127,7 @@ get_shadow_memory_for_matched_object(
   return result;
 }
 
-optionalt<exprt> get_shadow_memory(
+std::optional<exprt> get_shadow_memory(
   const exprt &expr,
   const std::vector<exprt> &value_set,
   const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
diff --git a/src/goto-symex/shadow_memory_util.h b/src/goto-symex/shadow_memory_util.h
index abe4e70be94..5f2de25c277 100644
--- a/src/goto-symex/shadow_memory_util.h
+++ b/src/goto-symex/shadow_memory_util.h
@@ -193,7 +193,7 @@ bool check_value_set_contains_only_null_ptr(
 ///    set, then we get back an `if e1 then e2 else (if e3 else e4...`
 ///    expression, where `e1`, `e3`, ... are guards (conditions) and `e2`, `e4`,
 ///    etc are the possible values of the object within the value set.
-optionalt<exprt> get_shadow_memory(
+std::optional<exprt> get_shadow_memory(
   const exprt &expr,
   const std::vector<exprt> &value_set,
   const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
diff --git a/src/goto-symex/symex_assign.h b/src/goto-symex/symex_assign.h
index 42738414b63..2d8fa1611a7 100644
--- a/src/goto-symex/symex_assign.h
+++ b/src/goto-symex/symex_assign.h
@@ -28,7 +28,7 @@ class symex_assignt
 {
 public:
   symex_assignt(
-    optionalt<shadow_memoryt> shadow_memory,
+    std::optional<shadow_memoryt> shadow_memory,
     goto_symex_statet &state,
     symex_targett::assignment_typet assignment_type,
     const namespacet &ns,
@@ -60,7 +60,7 @@ class symex_assignt
     exprt::operandst &guard);
 
 private:
-  optionalt<shadow_memoryt> shadow_memory;
+  std::optional<shadow_memoryt> shadow_memory;
   goto_symex_statet &state;
   symex_targett::assignment_typet assignment_type;
   const namespacet &ns;
diff --git a/src/goto-symex/symex_builtin_functions.cpp b/src/goto-symex/symex_builtin_functions.cpp
index ca290a7090d..6dbe4da9436 100644
--- a/src/goto-symex/symex_builtin_functions.cpp
+++ b/src/goto-symex/symex_builtin_functions.cpp
@@ -25,7 +25,7 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include "path_storage.h"
 
-inline static optionalt<typet> c_sizeof_type_rec(const exprt &expr)
+inline static std::optional<typet> c_sizeof_type_rec(const exprt &expr)
 {
   const irept &sizeof_type=expr.find(ID_C_c_sizeof_type);
 
@@ -57,7 +57,7 @@ void goto_symext::symex_allocate(
     return; // ignore
 
   exprt size = to_binary_expr(code).op0();
-  optionalt<typet> object_type;
+  std::optional<typet> object_type;
   auto function_symbol = outer_symbol_table.lookup(state.source.function_id);
   INVARIANT(function_symbol, "function associated with allocation not found");
   const irep_idt &mode = function_symbol->mode;
@@ -341,7 +341,7 @@ static irep_idt get_string_argument(const exprt &src, const namespacet &ns)
 
 /// Return an expression if \p operands fulfills all criteria that we expect of
 /// the expression to be a variable argument list.
-static optionalt<exprt> get_va_args(const exprt::operandst &operands)
+static std::optional<exprt> get_va_args(const exprt::operandst &operands)
 {
   if(operands.size() != 2)
     return {};
@@ -379,7 +379,7 @@ void goto_symext::symex_printf(
   std::list<exprt> args;
 
   // we either have any number of operands or a va_list as second operand
-  optionalt<exprt> va_args = get_va_args(operands);
+  std::optional<exprt> va_args = get_va_args(operands);
 
   if(!va_args.has_value())
   {
@@ -475,7 +475,7 @@ void goto_symext::symex_cpp_new(
      code.get(ID_statement) == ID_java_new_array_data);
 
   // value
-  optionalt<typet> type;
+  std::optional<typet> type;
   if(do_array)
   {
     exprt size_arg =
diff --git a/src/goto-symex/symex_goto.cpp b/src/goto-symex/symex_goto.cpp
index b0f82868f6e..404f04fec72 100644
--- a/src/goto-symex/symex_goto.cpp
+++ b/src/goto-symex/symex_goto.cpp
@@ -72,13 +72,13 @@ void goto_symext::apply_goto_condition(
 /// \param symbol_expr: The symbol expression in the condition
 /// \param other_operand: The other expression in the condition; we only support
 ///   an address of expression, a typecast of an address of expression or a
-///   null pointer, and return an empty optionalt in all other cases
+///   null pointer, and return an empty std::optional in all other cases
 /// \param value_set: The value-set for looking up what the symbol can point to
 /// \param language_mode: The language mode
 /// \param ns: A namespace
 /// \return If we were able to evaluate the condition as true or false then we
-///   return that, otherwise we return an empty optionalt
-static optionalt<renamedt<exprt, L2>> try_evaluate_pointer_comparison(
+///   return that, otherwise we return an empty std::optional
+static std::optional<renamedt<exprt, L2>> try_evaluate_pointer_comparison(
   const irep_idt &operation,
   const symbol_exprt &symbol_expr,
   const exprt &other_operand,
@@ -179,8 +179,8 @@ static optionalt<renamedt<exprt, L2>> try_evaluate_pointer_comparison(
 /// \param language_mode: The language mode
 /// \param ns: A namespace
 /// \return If we were able to evaluate the condition as true or false then we
-///   return that, otherwise we return an empty optionalt
-static optionalt<renamedt<exprt, L2>> try_evaluate_pointer_comparison(
+///   return that, otherwise we return an empty std::optional
+static std::optional<renamedt<exprt, L2>> try_evaluate_pointer_comparison(
   const renamedt<exprt, L2> &renamed_expr,
   const value_sett &value_set,
   const irep_idt &language_mode,
diff --git a/src/goto-symex/symex_main.cpp b/src/goto-symex/symex_main.cpp
index bc1d420f71b..ab929728998 100644
--- a/src/goto-symex/symex_main.cpp
+++ b/src/goto-symex/symex_main.cpp
@@ -754,18 +754,18 @@ void goto_symext::kill_instruction_local_symbols(statet &state)
 /// multiple times)
 /// \param expr: The expression to examine
 /// \return If only one unique symbol occurs in \p expr then return it;
-///   otherwise return an empty optionalt
-static optionalt<symbol_exprt>
+///   otherwise return an empty std::optional
+static std::optional<symbol_exprt>
 find_unique_pointer_typed_symbol(const exprt &expr)
 {
-  optionalt<symbol_exprt> return_value;
+  std::optional<symbol_exprt> return_value;
   for(auto it = expr.depth_cbegin(); it != expr.depth_cend(); ++it)
   {
     const symbol_exprt *symbol_expr = expr_try_dynamic_cast<symbol_exprt>(*it);
     if(symbol_expr && can_cast_type<pointer_typet>(symbol_expr->type()))
     {
       // If we already have a potential return value, check if it is the same
-      // symbol, and return an empty optionalt if not
+      // symbol, and return an empty std::optional if not
       if(return_value && *symbol_expr != *return_value)
       {
         return {};
@@ -789,7 +789,7 @@ void goto_symext::try_filter_value_sets(
 {
   condition = state.rename<L1>(std::move(condition), ns).get();
 
-  optionalt<symbol_exprt> symbol_expr =
+  std::optional<symbol_exprt> symbol_expr =
     find_unique_pointer_typed_symbol(condition);
 
   if(!symbol_expr)
diff --git a/src/goto-synthesizer/cegis_verifier.cpp b/src/goto-synthesizer/cegis_verifier.cpp
index 176343c6152..483fe94019e 100644
--- a/src/goto-synthesizer/cegis_verifier.cpp
+++ b/src/goto-synthesizer/cegis_verifier.cpp
@@ -546,7 +546,7 @@ void cegis_verifiert::restore_functions()
   }
 }
 
-optionalt<cext> cegis_verifiert::verify()
+std::optional<cext> cegis_verifiert::verify()
 {
   // This method does the following three things to verify the `goto_model` and
   // return a formatted counterexample if there is any violated property.
@@ -617,7 +617,7 @@ optionalt<cext> cegis_verifiert::verify()
   if(result == resultt::PASS)
   {
     restore_functions();
-    return optionalt<cext>();
+    return std::optional<cext>();
   }
 
   if(result == resultt::ERROR || result == resultt::UNKNOWN)
@@ -660,7 +660,7 @@ optionalt<cext> cegis_verifiert::verify()
   if(target_violation == properties.end())
   {
     restore_functions();
-    return optionalt<cext>();
+    return std::optional<cext>();
   }
 
   target_violation_id = target_violation->first;
diff --git a/src/goto-synthesizer/cegis_verifier.h b/src/goto-synthesizer/cegis_verifier.h
index 481246a6688..dc1e1aaa5be 100644
--- a/src/goto-synthesizer/cegis_verifier.h
+++ b/src/goto-synthesizer/cegis_verifier.h
@@ -114,9 +114,9 @@ class cegis_verifiert
   {
   }
 
-  /// Verify `goto_model`. Return an empty `optionalt if there is no violation.
-  /// Otherwise, return the formatted counterexample.
-  optionalt<cext> verify();
+  /// Verify `goto_model`. Return an empty `std::optional` if there is no
+  /// violation. Otherwise, return the formatted counterexample.
+  std::optional<cext> verify();
 
   /// Result counterexample.
   propertiest properties;
diff --git a/src/linking/static_lifetime_init.cpp b/src/linking/static_lifetime_init.cpp
index ece82ad5507..88432dfbf2d 100644
--- a/src/linking/static_lifetime_init.cpp
+++ b/src/linking/static_lifetime_init.cpp
@@ -21,7 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include <set>
 
-static optionalt<codet> static_lifetime_init(
+static std::optional<codet> static_lifetime_init(
   const irep_idt &identifier,
   symbol_table_baset &symbol_table)
 {
diff --git a/src/memory-analyzer/analyze_symbol.cpp b/src/memory-analyzer/analyze_symbol.cpp
index 000081db62e..645ec3c2725 100644
--- a/src/memory-analyzer/analyze_symbol.cpp
+++ b/src/memory-analyzer/analyze_symbol.cpp
@@ -86,7 +86,7 @@ mp_integer gdb_value_extractort::get_malloc_size(irep_idt name)
     return scope_it->size();
 }
 
-optionalt<std::string> gdb_value_extractort::get_malloc_pointee(
+std::optional<std::string> gdb_value_extractort::get_malloc_pointee(
   const memory_addresst &point,
   mp_integer member_size)
 {
diff --git a/src/memory-analyzer/analyze_symbol.h b/src/memory-analyzer/analyze_symbol.h
index 569c0f36fe6..e37f6fe6765 100644
--- a/src/memory-analyzer/analyze_symbol.h
+++ b/src/memory-analyzer/analyze_symbol.h
@@ -185,7 +185,7 @@ class gdb_value_extractort
   /// \param point: potentially dynamically allocated memory address
   /// \param member_size: size of each allocated element
   /// \return pointee as a string if we have a record of the allocation
-  optionalt<std::string>
+  std::optional<std::string>
   get_malloc_pointee(const memory_addresst &point, mp_integer member_size);
 
   /// Wrapper for call get_offset_pointer_bits
diff --git a/src/memory-analyzer/gdb_api.cpp b/src/memory-analyzer/gdb_api.cpp
index 3ad72ffda24..5cc6d4a27f2 100644
--- a/src/memory-analyzer/gdb_api.cpp
+++ b/src/memory-analyzer/gdb_api.cpp
@@ -465,7 +465,7 @@ gdb_apit::pointer_valuet gdb_apit::get_memory(const std::string &expr)
   if(!b)
     return pointer_valuet{};
 
-  optionalt<std::string> opt_string;
+  std::optional<std::string> opt_string;
   const std::string string = result[4];
 
   if(!string.empty())
@@ -494,7 +494,7 @@ gdb_apit::pointer_valuet gdb_apit::get_memory(const std::string &expr)
   return pointer_valuet(result[1], result[2], result[3], opt_string, true);
 }
 
-optionalt<std::string> gdb_apit::get_value(const std::string &expr)
+std::optional<std::string> gdb_apit::get_value(const std::string &expr)
 {
   PRECONDITION(gdb_state == gdb_statet::STOPPED);
 
diff --git a/src/memory-analyzer/gdb_api.h b/src/memory-analyzer/gdb_api.h
index 6edff80a536..f23c14c89aa 100644
--- a/src/memory-analyzer/gdb_api.h
+++ b/src/memory-analyzer/gdb_api.h
@@ -79,7 +79,7 @@ class gdb_apit
       const std::string &address = "",
       const std::string &pointee = "",
       const std::string &character = "",
-      const optionalt<std::string> &string = {},
+      const std::optional<std::string> &string = {},
       const bool valid = false)
       : address(address),
         pointee(pointee),
@@ -92,7 +92,7 @@ class gdb_apit
     memory_addresst address;
     std::string pointee;
     std::string character;
-    optionalt<std::string> string;
+    std::optional<std::string> string;
 
     bool has_known_offset() const
     {
@@ -127,7 +127,7 @@ class gdb_apit
   /// \param expr: an expression of pointer type (e.g., `&x` with `x` being of
   ///   type `int` or `p` with `p` being of type `int *`)
   /// \return memory address in hex format
-  optionalt<std::string> get_value(const std::string &expr);
+  std::optional<std::string> get_value(const std::string &expr);
 
   /// Get the value of a pointer associated with \p expr
   /// \param expr: the expression to be analyzed
diff --git a/src/pointer-analysis/add_failed_symbols.cpp b/src/pointer-analysis/add_failed_symbols.cpp
index 66f0739b902..f53947a767b 100644
--- a/src/pointer-analysis/add_failed_symbols.cpp
+++ b/src/pointer-analysis/add_failed_symbols.cpp
@@ -87,7 +87,7 @@ void add_failed_symbols(symbol_table_baset &symbol_table)
     add_failed_symbol_if_needed(*symbol, symbol_table);
 }
 
-optionalt<symbol_exprt>
+std::optional<symbol_exprt>
 get_failed_symbol(const symbol_exprt &expr, const namespacet &ns)
 {
   const symbolt &symbol=ns.lookup(expr);
diff --git a/src/pointer-analysis/add_failed_symbols.h b/src/pointer-analysis/add_failed_symbols.h
index d3b3ac49574..c52a24b3e71 100644
--- a/src/pointer-analysis/add_failed_symbols.h
+++ b/src/pointer-analysis/add_failed_symbols.h
@@ -13,7 +13,6 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_POINTER_ANALYSIS_ADD_FAILED_SYMBOLS_H
 
 #include <util/expr.h>
-#include <util/optional.h>
 
 class symbol_table_baset;
 class symbolt;
@@ -32,7 +31,7 @@ irep_idt failed_symbol_id(const irep_idt &identifier);
 /// \param ns: global namespace
 /// \return symbol expression for the failed-dereference symbol, or an empty
 ///   optional if none exists.
-optionalt<symbol_exprt>
+std::optional<symbol_exprt>
 get_failed_symbol(const symbol_exprt &expr, const namespacet &ns);
 
 /// Return true if, and only if, \p expr is the result of failed dereferencing.
diff --git a/src/pointer-analysis/value_set.cpp b/src/pointer-analysis/value_set.cpp
index 7a3543f5c2a..ca0ef7a0cbb 100644
--- a/src/pointer-analysis/value_set.cpp
+++ b/src/pointer-analysis/value_set.cpp
@@ -449,7 +449,7 @@ static std::string strip_first_field_from_suffix(
   return suffix.substr(field.length() + 1);
 }
 
-optionalt<irep_idt> value_sett::get_index_of_symbol(
+std::optional<irep_idt> value_sett::get_index_of_symbol(
   irep_idt identifier,
   const typet &type,
   const std::string &suffix,
@@ -698,10 +698,10 @@ void value_sett::get_value_set_rec(
       throw expr.id_string()+" expected to have at least two operands";
 
     object_mapt pointer_expr_set;
-    optionalt<mp_integer> i;
+    std::optional<mp_integer> i;
 
     // special case for plus/minus and exactly one pointer
-    optionalt<exprt> ptr_operand;
+    std::optional<exprt> ptr_operand;
     if(
       expr_type.id() == ID_pointer &&
       (expr.id() == ID_plus || expr.id() == ID_minus))
diff --git a/src/pointer-analysis/value_set.h b/src/pointer-analysis/value_set.h
index 3d00dbf7e9c..5c71946acd8 100644
--- a/src/pointer-analysis/value_set.h
+++ b/src/pointer-analysis/value_set.h
@@ -78,7 +78,7 @@ class value_sett
 
   /// Represents the offset into an object: either a unique integer offset,
   /// or an unknown value, represented by `!offset`.
-  typedef optionalt<mp_integer> offsett;
+  typedef std::optional<mp_integer> offsett;
 
   /// Represents a set of expressions (`exprt` instances) with corresponding
   /// offsets (`offsett` instances). This is the RHS set of a single row of
@@ -417,7 +417,7 @@ class value_sett
   /// \param ns: The global namespace, for following \p type if it is a
   ///   struct tag type or a union tag type
   /// \return The index if the symbol is known, else `nullopt`.
-  optionalt<irep_idt> get_index_of_symbol(
+  std::optional<irep_idt> get_index_of_symbol(
     irep_idt identifier,
     const typet &type,
     const std::string &suffix,
diff --git a/src/pointer-analysis/value_set_dereference.cpp b/src/pointer-analysis/value_set_dereference.cpp
index 924480fbe25..74ef37f4911 100644
--- a/src/pointer-analysis/value_set_dereference.cpp
+++ b/src/pointer-analysis/value_set_dereference.cpp
@@ -103,8 +103,8 @@ static json_objectt value_set_dereference_stats_to_json(
 
 /// If `expr` is of the form (c1 ? e1[o1] : c2 ? e2[o2] : c3 ? ...)
 /// then return `c1 ? e1[o1 + offset] : e2[o2 + offset] : c3 ? ...`
-/// otherwise return an empty optionalt.
-static optionalt<exprt>
+/// otherwise return an empty std::optional.
+static std::optional<exprt>
 try_add_offset_to_indices(const exprt &expr, const exprt &offset_elements)
 {
   if(const auto *index_expr = expr_try_dynamic_cast<index_exprt>(expr))
@@ -773,7 +773,7 @@ bool value_set_dereferencet::memory_model_bytes(
   auto from_type_element_type_size =
     from_type.id() == ID_array
       ? pointer_offset_size(to_array_type(from_type).element_type(), ns)
-      : optionalt<mp_integer>{};
+      : std::optional<mp_integer>{};
 
   auto to_type_size = pointer_offset_size(to_type, ns);
 
diff --git a/src/pointer-analysis/value_set_fi.h b/src/pointer-analysis/value_set_fi.h
index 859a8fc38d5..8b3ad907dde 100644
--- a/src/pointer-analysis/value_set_fi.h
+++ b/src/pointer-analysis/value_set_fi.h
@@ -57,7 +57,7 @@ class value_set_fit
 
   /// Represents the offset into an object: either a unique integer offset,
   /// or an unknown value, represented by `!offset`.
-  typedef optionalt<mp_integer> offsett;
+  typedef std::optional<mp_integer> offsett;
   bool offset_is_zero(const offsett &offset) const
   {
     return offset && offset->is_zero();
diff --git a/src/solvers/README.md b/src/solvers/README.md
index 2a19e79f88b..075bedb5355 100644
--- a/src/solvers/README.md
+++ b/src/solvers/README.md
@@ -181,7 +181,7 @@ Note: `bvt` mentioned below is an alias to a vector of literalt.
 Which takes an exprt then calls the associated transformation functions to
 generate the \ref literalt vector to then pass to the internal \ref propt instance.
 
-`const bvt & boolbvt::convert_bv(const exprt &expr, optionalt<std::size_t> expected_width)`
+`const bvt & boolbvt::convert_bv(const exprt &expr, std::optional<std::size_t> expected_width)`
 
 Similar to convert_bitvector except it also provides basic caching and
 freezing results for incremental solving. It calls convert_bitvector
diff --git a/src/solvers/flattening/arrays.cpp b/src/solvers/flattening/arrays.cpp
index 360f68f0f99..cfc6297791a 100644
--- a/src/solvers/flattening/arrays.cpp
+++ b/src/solvers/flattening/arrays.cpp
@@ -715,7 +715,7 @@ void arrayst::add_array_constraints_array_constant(
       // We have a constant index - just pick the element at that index from the
       // array constant.
 
-      const optionalt<std::size_t> i =
+      const std::optional<std::size_t> i =
         numeric_cast<std::size_t>(to_constant_expr(index));
       // if the access is out of bounds, we leave it unconstrained
       if(!i.has_value() || *i >= operands.size())
diff --git a/src/solvers/flattening/boolbv.cpp b/src/solvers/flattening/boolbv.cpp
index 1ee94ac9f54..3f026d4b3b7 100644
--- a/src/solvers/flattening/boolbv.cpp
+++ b/src/solvers/flattening/boolbv.cpp
@@ -34,8 +34,9 @@ endianness_mapt boolbvt::endianness_map(const typet &type) const
 /// Convert expression to vector of literalts, using an internal
 /// cache to speed up conversion if available. Also assert the resultant
 /// vector is of a specific size, and freeze any elements if appropriate.
-const bvt &
-boolbvt::convert_bv(const exprt &expr, optionalt<std::size_t> expected_width)
+const bvt &boolbvt::convert_bv(
+  const exprt &expr,
+  std::optional<std::size_t> expected_width)
 {
   // check cache first
   std::pair<bv_cachet::iterator, bool> cache_result=
diff --git a/src/solvers/flattening/boolbv.h b/src/solvers/flattening/boolbv.h
index 882a3eb1f8f..fb88fa73fd7 100644
--- a/src/solvers/flattening/boolbv.h
+++ b/src/solvers/flattening/boolbv.h
@@ -59,7 +59,7 @@ class boolbvt:public arrayst
 
   virtual const bvt &convert_bv( // check cache
     const exprt &expr,
-    const optionalt<std::size_t> expected_width = {});
+    const std::optional<std::size_t> expected_width = {});
 
   virtual bvt convert_bitvector(const exprt &expr); // no cache
 
diff --git a/src/solvers/flattening/boolbv_map.h b/src/solvers/flattening/boolbv_map.h
index ee6b7425955..a9ba3063079 100644
--- a/src/solvers/flattening/boolbv_map.h
+++ b/src/solvers/flattening/boolbv_map.h
@@ -53,14 +53,15 @@ class boolbv_mapt
     const irep_idt &identifier,
     const typet &type);
 
-  optionalt<std::reference_wrapper<const map_entryt>>
+  std::optional<std::reference_wrapper<const map_entryt>>
   get_map_entry(const irep_idt &identifier) const
   {
     const auto entry = mapping.find(identifier);
     if(entry == mapping.end())
       return {};
 
-    return optionalt<std::reference_wrapper<const map_entryt>>(entry->second);
+    return std::optional<std::reference_wrapper<const map_entryt>>(
+      entry->second);
   }
 
   const mappingt &get_mapping() const
diff --git a/src/solvers/flattening/boolbv_overflow.cpp b/src/solvers/flattening/boolbv_overflow.cpp
index dcebd389089..a32dd19a13b 100644
--- a/src/solvers/flattening/boolbv_overflow.cpp
+++ b/src/solvers/flattening/boolbv_overflow.cpp
@@ -117,7 +117,7 @@ literalt boolbvt::convert_binary_overflow(const binary_overflow_exprt &expr)
   const bvt &bv1 = convert_bv(
     expr.rhs(),
     can_cast_expr<mult_overflow_exprt>(expr)
-      ? optionalt<std::size_t>{bv0.size()}
+      ? std::optional<std::size_t>{bv0.size()}
       : std::nullopt);
 
   const bv_utilst::representationt rep =
diff --git a/src/solvers/flattening/boolbv_quantifier.cpp b/src/solvers/flattening/boolbv_quantifier.cpp
index 0887966fb2c..5ca7c77b243 100644
--- a/src/solvers/flattening/boolbv_quantifier.cpp
+++ b/src/solvers/flattening/boolbv_quantifier.cpp
@@ -22,7 +22,7 @@ static bool expr_eq(const exprt &expr1, const exprt &expr2)
 /// To obtain the min value for the quantifier variable of the specified
 /// forall/exists operator. The min variable is in the form of "!(var_expr >
 /// constant)".
-static optionalt<constant_exprt>
+static std::optional<constant_exprt>
 get_quantifier_var_min(const exprt &var_expr, const exprt &quantifier_expr)
 {
   if(quantifier_expr.id()==ID_or)
@@ -74,7 +74,7 @@ get_quantifier_var_min(const exprt &var_expr, const exprt &quantifier_expr)
 
 /// To obtain the max value for the quantifier variable of the specified
 /// forall/exists operator.
-static optionalt<constant_exprt>
+static std::optional<constant_exprt>
 get_quantifier_var_max(const exprt &var_expr, const exprt &quantifier_expr)
 {
   if(quantifier_expr.id()==ID_or)
@@ -149,7 +149,7 @@ get_quantifier_var_max(const exprt &var_expr, const exprt &quantifier_expr)
   return {};
 }
 
-static optionalt<exprt> eager_quantifier_instantiation(
+static std::optional<exprt> eager_quantifier_instantiation(
   const quantifier_exprt &expr,
   const namespacet &ns)
 {
@@ -199,9 +199,9 @@ static optionalt<exprt> eager_quantifier_instantiation(
       UNREACHABLE;
   }
 
-  const optionalt<constant_exprt> min_i =
+  const std::optional<constant_exprt> min_i =
     get_quantifier_var_min(var_expr, where_simplified);
-  const optionalt<constant_exprt> max_i =
+  const std::optional<constant_exprt> max_i =
     get_quantifier_var_max(var_expr, where_simplified);
 
   if(!min_i.has_value() || !max_i.has_value())
diff --git a/src/solvers/flattening/boolbv_width.h b/src/solvers/flattening/boolbv_width.h
index 24c8909fe00..d6e66f75c09 100644
--- a/src/solvers/flattening/boolbv_width.h
+++ b/src/solvers/flattening/boolbv_width.h
@@ -28,7 +28,7 @@ class boolbv_widtht
     return entry_opt->total_width;
   }
 
-  virtual optionalt<std::size_t> get_width_opt(const typet &type) const
+  virtual std::optional<std::size_t> get_width_opt(const typet &type) const
   {
     const auto &entry_opt = get_entry(type);
     if(!entry_opt.has_value())
@@ -56,7 +56,7 @@ class boolbv_widtht
     std::size_t total_width;
     std::vector<membert> members;
   };
-  using entryt = optionalt<defined_entryt>;
+  using entryt = std::optional<defined_entryt>;
 
   typedef std::unordered_map<typet, entryt, irep_hash> cachet;
 
diff --git a/src/solvers/flattening/bv_pointers.cpp b/src/solvers/flattening/bv_pointers.cpp
index be28f5eef2e..66af5ce4953 100644
--- a/src/solvers/flattening/bv_pointers.cpp
+++ b/src/solvers/flattening/bv_pointers.cpp
@@ -231,7 +231,7 @@ bv_pointerst::bv_pointerst(
 {
 }
 
-optionalt<bvt> bv_pointerst::convert_address_of_rec(const exprt &expr)
+std::optional<bvt> bv_pointerst::convert_address_of_rec(const exprt &expr)
 {
   if(expr.id()==ID_symbol)
   {
diff --git a/src/solvers/flattening/bv_pointers.h b/src/solvers/flattening/bv_pointers.h
index 151a1205c63..57958d2e9f3 100644
--- a/src/solvers/flattening/bv_pointers.h
+++ b/src/solvers/flattening/bv_pointers.h
@@ -51,7 +51,7 @@ class bv_pointerst:public boolbvt
   exprt
   bv_get_rec(const exprt &, const bvt &, std::size_t offset) const override;
 
-  [[nodiscard]] optionalt<bvt> convert_address_of_rec(const exprt &);
+  [[nodiscard]] std::optional<bvt> convert_address_of_rec(const exprt &);
 
   [[nodiscard]] bvt
   offset_arithmetic(const pointer_typet &, const bvt &, const mp_integer &);
diff --git a/src/solvers/prop/prop_conv_solver.cpp b/src/solvers/prop/prop_conv_solver.cpp
index b82ad7f342b..7ca6632f1f5 100644
--- a/src/solvers/prop/prop_conv_solver.cpp
+++ b/src/solvers/prop/prop_conv_solver.cpp
@@ -74,7 +74,7 @@ literalt prop_conv_solvert::get_literal(const irep_idt &identifier)
   return literal;
 }
 
-optionalt<bool> prop_conv_solvert::get_bool(const exprt &expr) const
+std::optional<bool> prop_conv_solvert::get_bool(const exprt &expr) const
 {
   // trivial cases
 
diff --git a/src/solvers/prop/prop_conv_solver.h b/src/solvers/prop/prop_conv_solver.h
index ba41bc91222..a32ce943188 100644
--- a/src/solvers/prop/prop_conv_solver.h
+++ b/src/solvers/prop/prop_conv_solver.h
@@ -110,7 +110,7 @@ class prop_conv_solvert : public conflict_providert,
   /// Get a _boolean_ value from the model if the formula is satisfiable.
   /// If the argument is not a boolean expression from the formula,
   /// {} is returned.
-  virtual optionalt<bool> get_bool(const exprt &expr) const;
+  virtual std::optional<bool> get_bool(const exprt &expr) const;
 
   virtual literalt convert_rest(const exprt &expr);
   virtual literalt convert_bool(const exprt &expr);
diff --git a/src/solvers/smt2/smt2irep.cpp b/src/solvers/smt2/smt2irep.cpp
index 14e75e16863..9eeeb58921a 100644
--- a/src/solvers/smt2/smt2irep.cpp
+++ b/src/solvers/smt2/smt2irep.cpp
@@ -22,13 +22,13 @@ class smt2irept:public smt2_tokenizert
   {
   }
 
-  optionalt<irept> operator()();
+  std::optional<irept> operator()();
 
 protected:
   messaget log;
 };
 
-optionalt<irept> smt2irept::operator()()
+std::optional<irept> smt2irept::operator()()
 {
   try
   {
@@ -88,7 +88,8 @@ optionalt<irept> smt2irept::operator()()
   }
 }
 
-optionalt<irept> smt2irep(std::istream &in, message_handlert &message_handler)
+std::optional<irept>
+smt2irep(std::istream &in, message_handlert &message_handler)
 {
   return smt2irept(in, message_handler)();
 }
diff --git a/src/solvers/smt2/smt2irep.h b/src/solvers/smt2/smt2irep.h
index f34ece51ba2..bc2a03748c3 100644
--- a/src/solvers/smt2/smt2irep.h
+++ b/src/solvers/smt2/smt2irep.h
@@ -11,14 +11,13 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_SOLVERS_SMT2_SMT2IREP_H
 
 #include <iosfwd>
-
-#include <util/optional.h>
+#include <optional>
 
 class irept;
 class message_handlert;
 
 /// returns an irep for an SMT-LIB2 expression read from a given stream
 /// returns {} when EOF is encountered before reading non-whitespace input
-optionalt<irept> smt2irep(std::istream &, message_handlert &);
+std::optional<irept> smt2irep(std::istream &, message_handlert &);
 
 #endif // CPROVER_SOLVERS_SMT2_SMT2IREP_H
diff --git a/src/solvers/strings/array_pool.cpp b/src/solvers/strings/array_pool.cpp
index 39a0ec14147..4b88e8fad56 100644
--- a/src/solvers/strings/array_pool.cpp
+++ b/src/solvers/strings/array_pool.cpp
@@ -44,7 +44,7 @@ exprt array_poolt::get_or_create_length(const array_string_exprt &s)
   return emplace_result.first->second;
 }
 
-optionalt<exprt>
+std::optional<exprt>
 array_poolt::get_length_if_exists(const array_string_exprt &s) const
 {
   auto find_result = length_of_array.find(s);
diff --git a/src/solvers/strings/array_pool.h b/src/solvers/strings/array_pool.h
index 99bb9a83513..fc210f76f5f 100644
--- a/src/solvers/strings/array_pool.h
+++ b/src/solvers/strings/array_pool.h
@@ -68,7 +68,7 @@ class array_poolt final
   /// return an empty optional.
   /// \param s: array expression representing a string
   /// \return expression for the length of `s`, or empty optional
-  optionalt<exprt> get_length_if_exists(const array_string_exprt &s) const;
+  std::optional<exprt> get_length_if_exists(const array_string_exprt &s) const;
 
   void insert(const exprt &pointer_expr, const array_string_exprt &array);
 
diff --git a/src/solvers/strings/string_builtin_function.cpp b/src/solvers/strings/string_builtin_function.cpp
index b3e08da91cc..689818c4aaf 100644
--- a/src/solvers/strings/string_builtin_function.cpp
+++ b/src/solvers/strings/string_builtin_function.cpp
@@ -21,7 +21,7 @@ string_transformation_builtin_functiont::
   result = array_pool.find(fun_args[1], fun_args[0]);
 }
 
-optionalt<std::vector<mp_integer>> eval_string(
+std::optional<std::vector<mp_integer>> eval_string(
   const array_string_exprt &a,
   const std::function<exprt(const exprt &)> &get_value)
 {
@@ -73,7 +73,7 @@ make_string(const std::vector<mp_integer> &array, const array_typet &array_type)
   return make_string(array.begin(), array.end(), array_type);
 }
 
-optionalt<exprt> string_concat_char_builtin_functiont::eval(
+std::optional<exprt> string_concat_char_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   auto input_opt = eval_string(input, get_value);
@@ -126,7 +126,7 @@ exprt string_concat_char_builtin_functiont::length_constraint() const
   return length_constraint_for_concat_char(result, input, array_pool);
 }
 
-optionalt<exprt> string_set_char_builtin_functiont::eval(
+std::optional<exprt> string_set_char_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   auto input_opt = eval_string(input, get_value);
@@ -217,7 +217,7 @@ static bool eval_is_upper_case(const mp_integer &c)
          (0xd8 <= c && c <= 0xde);
 }
 
-optionalt<exprt> string_to_lower_case_builtin_functiont::eval(
+std::optional<exprt> string_to_lower_case_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   auto input_opt = eval_string(input, get_value);
@@ -313,7 +313,7 @@ string_constraintst string_to_lower_case_builtin_functiont::constraints(
   return constraints;
 }
 
-optionalt<exprt> string_to_upper_case_builtin_functiont::eval(
+std::optional<exprt> string_to_upper_case_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   auto input_opt = eval_string(input, get_value);
@@ -380,7 +380,7 @@ string_creation_builtin_functiont::string_creation_builtin_functiont(
   arg = fun_args[2];
 }
 
-optionalt<exprt> string_of_int_builtin_functiont::eval(
+std::optional<exprt> string_of_int_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   const auto arg_value = numeric_cast<mp_integer>(get_value(arg));
diff --git a/src/solvers/strings/string_builtin_function.h b/src/solvers/strings/string_builtin_function.h
index 510f909ee3b..d515c7f4652 100644
--- a/src/solvers/strings/string_builtin_function.h
+++ b/src/solvers/strings/string_builtin_function.h
@@ -75,7 +75,7 @@ class string_builtin_functiont
   string_builtin_functiont(const string_builtin_functiont &) = delete;
   virtual ~string_builtin_functiont() = default;
 
-  virtual optionalt<array_string_exprt> string_result() const
+  virtual std::optional<array_string_exprt> string_result() const
   {
     return {};
   }
@@ -89,7 +89,7 @@ class string_builtin_functiont
   /// attempt to find the result of the builtin function.
   /// If not enough information can be gathered from `get_value`, return an
   /// empty optional.
-  virtual optionalt<exprt>
+  virtual std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const = 0;
 
   virtual std::string name() const = 0;
@@ -154,7 +154,7 @@ class string_transformation_builtin_functiont : public string_builtin_functiont
     const std::vector<exprt> &fun_args,
     array_poolt &array_pool);
 
-  optionalt<array_string_exprt> string_result() const override
+  std::optional<array_string_exprt> string_result() const override
   {
     return result;
   }
@@ -189,7 +189,7 @@ class string_concat_char_builtin_functiont
     character = fun_args[3];
   }
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
@@ -227,7 +227,7 @@ class string_set_char_builtin_functiont
     character = fun_args[4];
   }
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
@@ -258,7 +258,7 @@ class string_to_lower_case_builtin_functiont
   {
   }
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
@@ -307,7 +307,7 @@ class string_to_upper_case_builtin_functiont
   {
   }
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
@@ -348,7 +348,7 @@ class string_creation_builtin_functiont : public string_builtin_functiont
     const std::vector<exprt> &fun_args,
     array_poolt &array_pool);
 
-  optionalt<array_string_exprt> string_result() const override
+  std::optional<array_string_exprt> string_result() const override
   {
     return result;
   }
@@ -376,7 +376,7 @@ class string_of_int_builtin_functiont : public string_creation_builtin_functiont
       radix = from_integer(10, arg.type());
   };
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
@@ -415,7 +415,7 @@ class string_builtin_function_with_no_evalt : public string_builtin_functiont
 {
 public:
   function_application_exprt function_application;
-  optionalt<array_string_exprt> string_res;
+  std::optional<array_string_exprt> string_res;
   std::vector<array_string_exprt> string_args;
   std::vector<exprt> args;
 
@@ -434,12 +434,12 @@ class string_builtin_function_with_no_evalt : public string_builtin_functiont
   {
     return std::vector<array_string_exprt>(string_args);
   }
-  optionalt<array_string_exprt> string_result() const override
+  std::optional<array_string_exprt> string_result() const override
   {
     return string_res;
   }
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &) const override
   {
     return {};
@@ -460,7 +460,7 @@ class string_builtin_function_with_no_evalt : public string_builtin_functiont
 /// Given a function `get_value` which gives a valuation to expressions, attempt
 /// to find the current value of the array `a`. If the valuation of some
 /// characters are missing, then return an empty optional.
-optionalt<std::vector<mp_integer>> eval_string(
+std::optional<std::vector<mp_integer>> eval_string(
   const array_string_exprt &a,
   const std::function<exprt(const exprt &)> &get_value);
 
diff --git a/src/solvers/strings/string_constraint_generator.h b/src/solvers/strings/string_constraint_generator.h
index 1e36064f49f..f439e5f28b3 100644
--- a/src/solvers/strings/string_constraint_generator.h
+++ b/src/solvers/strings/string_constraint_generator.h
@@ -67,7 +67,7 @@ class string_constraint_generatort final
   /// Associate array to pointer, and array to length
   /// \return an expression if the given function application is one of
   ///   associate pointer and associate length
-  optionalt<exprt> make_array_pointer_association(
+  std::optional<exprt> make_array_pointer_association(
     const exprt &return_code,
     const function_application_exprt &expr);
 
diff --git a/src/solvers/strings/string_constraint_generator_main.cpp b/src/solvers/strings/string_constraint_generator_main.cpp
index acc8d874059..33dcb782a02 100644
--- a/src/solvers/strings/string_constraint_generator_main.cpp
+++ b/src/solvers/strings/string_constraint_generator_main.cpp
@@ -192,7 +192,8 @@ static irep_idt get_function_name(const function_application_exprt &expr)
   return to_symbol_expr(name).get_identifier();
 }
 
-optionalt<exprt> string_constraint_generatort::make_array_pointer_association(
+std::optional<exprt>
+string_constraint_generatort::make_array_pointer_association(
   const exprt &return_code,
   const function_application_exprt &expr)
 {
diff --git a/src/solvers/strings/string_constraint_generator_transformation.cpp b/src/solvers/strings/string_constraint_generator_transformation.cpp
index 6d82b14307d..fc33eaec861 100644
--- a/src/solvers/strings/string_constraint_generator_transformation.cpp
+++ b/src/solvers/strings/string_constraint_generator_transformation.cpp
@@ -269,7 +269,7 @@ string_constraint_generatort::add_axioms_for_trim(
 ///   not primitive chars.
 /// \param array_pool: pool of arrays representing strings
 /// \return Optional pair of two expressions
-static optionalt<std::pair<exprt, exprt>> to_char_pair(
+static std::optional<std::pair<exprt, exprt>> to_char_pair(
   exprt expr1,
   exprt expr2,
   std::function<array_string_exprt(const exprt &)> get_string_expr,
diff --git a/src/solvers/strings/string_constraint_generator_valueof.cpp b/src/solvers/strings/string_constraint_generator_valueof.cpp
index ccc02c05e48..039557734a1 100644
--- a/src/solvers/strings/string_constraint_generator_valueof.cpp
+++ b/src/solvers/strings/string_constraint_generator_valueof.cpp
@@ -421,7 +421,7 @@ string_constraint_generatort::add_axioms_for_characters_in_integer_string(
     // a digit, which is `max_string_length - 2` because of the space left for
     // a minus sign. That assumes that we were able to identify the radix. If we
     // weren't then we check for overflow on every index.
-    optionalt<exprt> no_overflow;
+    std::optional<exprt> no_overflow;
     if(size - 1 >= max_string_length - 2 || radix_ul == 0)
     {
       no_overflow = and_exprt{equal_exprt(sum, div_exprt(radix_sum, radix)),
diff --git a/src/solvers/strings/string_dependencies.cpp b/src/solvers/strings/string_dependencies.cpp
index 2a0ab220886..17a5105c8f8 100644
--- a/src/solvers/strings/string_dependencies.cpp
+++ b/src/solvers/strings/string_dependencies.cpp
@@ -165,7 +165,7 @@ static void add_dependency_to_string_subexprs(
   }
 }
 
-optionalt<exprt> string_dependenciest::eval(
+std::optional<exprt> string_dependenciest::eval(
   const array_string_exprt &s,
   const std::function<exprt(const exprt &)> &get_value) const
 {
@@ -194,7 +194,7 @@ void string_dependenciest::clean_cache()
     e.reset();
 }
 
-optionalt<exprt> add_node(
+std::optional<exprt> add_node(
   string_dependenciest &dependencies,
   const exprt &expr,
   array_poolt &array_pool,
diff --git a/src/solvers/strings/string_dependencies.h b/src/solvers/strings/string_dependencies.h
index 68b30868bc1..eac3cf3219a 100644
--- a/src/solvers/strings/string_dependencies.h
+++ b/src/solvers/strings/string_dependencies.h
@@ -64,7 +64,7 @@ class string_dependenciest
     // \todo should these we shared pointers?
     std::vector<std::size_t> dependencies;
     // builtin function of which it is the result
-    optionalt<std::size_t> result_from;
+    std::optional<std::size_t> result_from;
 
     explicit string_nodet(array_string_exprt e, const std::size_t index)
       : expr(std::move(e)), index(index)
@@ -101,7 +101,7 @@ class string_dependenciest
   /// of strings on which it depends
   /// Warning: eval uses a cache which must be cleaned everytime the valuations
   /// given by get_value can change.
-  optionalt<exprt> eval(
+  std::optional<exprt> eval(
     const array_string_exprt &s,
     const std::function<exprt(const exprt &)> &get_value) const;
 
@@ -169,7 +169,7 @@ class string_dependenciest
     }
   };
 
-  mutable std::vector<optionalt<exprt>> eval_string_cache;
+  mutable std::vector<std::optional<exprt>> eval_string_cache;
 
   /// Applies `f` on all nodes
   void for_each_node(const std::function<void(const nodet &)> &f) const;
@@ -197,7 +197,7 @@ class string_dependenciest
 ///   builtin function. Or an empty optional when no function applications has
 ///   been encountered
 /// \todo there should be a class with just the three functions we require here
-optionalt<exprt> add_node(
+std::optional<exprt> add_node(
   string_dependenciest &dependencies,
   const exprt &expr,
   array_poolt &array_pool,
diff --git a/src/solvers/strings/string_format_builtin_function.cpp b/src/solvers/strings/string_format_builtin_function.cpp
index c8f07ab666b..20ce1f8ab2a 100644
--- a/src/solvers/strings/string_format_builtin_function.cpp
+++ b/src/solvers/strings/string_format_builtin_function.cpp
@@ -516,7 +516,7 @@ static std::vector<mp_integer> eval_format_specifier(
   INVARIANT(false, "format specifier must belong to [bBhHsScCdoxXeEfgGaAtT%n]");
 }
 
-optionalt<exprt> string_format_builtin_functiont::eval(
+std::optional<exprt> string_format_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   if(!format_string.has_value())
diff --git a/src/solvers/strings/string_format_builtin_function.h b/src/solvers/strings/string_format_builtin_function.h
index 0b2d1112542..62d8a02eae9 100644
--- a/src/solvers/strings/string_format_builtin_function.h
+++ b/src/solvers/strings/string_format_builtin_function.h
@@ -65,7 +65,7 @@ class string_format_builtin_functiont final : public string_builtin_functiont
   array_string_exprt result;
   /// Only set when the format string is a constant. In the other case, the
   /// result will be non-deterministic
-  optionalt<std::string> format_string;
+  std::optional<std::string> format_string;
   std::vector<array_string_exprt> inputs;
 
   /// Constructor from arguments of a function application.
@@ -78,7 +78,7 @@ class string_format_builtin_functiont final : public string_builtin_functiont
     const std::vector<exprt> &fun_args,
     array_poolt &array_pool);
 
-  optionalt<array_string_exprt> string_result() const override
+  std::optional<array_string_exprt> string_result() const override
   {
     return result;
   }
@@ -88,7 +88,7 @@ class string_format_builtin_functiont final : public string_builtin_functiont
     return inputs;
   }
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
diff --git a/src/solvers/strings/string_insertion_builtin_function.cpp b/src/solvers/strings/string_insertion_builtin_function.cpp
index 62609758085..3135fddf276 100644
--- a/src/solvers/strings/string_insertion_builtin_function.cpp
+++ b/src/solvers/strings/string_insertion_builtin_function.cpp
@@ -62,7 +62,7 @@ std::vector<mp_integer> string_insertion_builtin_functiont::eval(
   return eval_result;
 }
 
-optionalt<exprt> string_insertion_builtin_functiont::eval(
+std::optional<exprt> string_insertion_builtin_functiont::eval(
   const std::function<exprt(const exprt &)> &get_value) const
 {
   const auto &input1_value = eval_string(input1, get_value);
diff --git a/src/solvers/strings/string_insertion_builtin_function.h b/src/solvers/strings/string_insertion_builtin_function.h
index 877d764aa2f..fbf03d38d53 100644
--- a/src/solvers/strings/string_insertion_builtin_function.h
+++ b/src/solvers/strings/string_insertion_builtin_function.h
@@ -31,7 +31,7 @@ class string_insertion_builtin_functiont : public string_builtin_functiont
     const std::vector<exprt> &fun_args,
     array_poolt &array_pool);
 
-  optionalt<array_string_exprt> string_result() const override
+  std::optional<array_string_exprt> string_result() const override
   {
     return result;
   }
@@ -46,7 +46,7 @@ class string_insertion_builtin_functiont : public string_builtin_functiont
     const std::vector<mp_integer> &input2_value,
     const std::vector<mp_integer> &args_value) const;
 
-  optionalt<exprt>
+  std::optional<exprt>
   eval(const std::function<exprt(const exprt &)> &get_value) const override;
 
   std::string name() const override
diff --git a/src/solvers/strings/string_refinement.cpp b/src/solvers/strings/string_refinement.cpp
index 155598dac6d..45cd53fffba 100644
--- a/src/solvers/strings/string_refinement.cpp
+++ b/src/solvers/strings/string_refinement.cpp
@@ -40,7 +40,7 @@ static bool is_valid_string_constraint(
   const namespacet &ns,
   const string_constraintt &constraint);
 
-static optionalt<exprt> find_counter_example(
+static std::optional<exprt> find_counter_example(
   const namespacet &ns,
   const exprt &axiom,
   const symbol_exprt &var,
@@ -106,14 +106,14 @@ static std::vector<exprt> instantiate(
   const std::unordered_map<string_not_contains_constraintt, symbol_exprt>
     &witnesses);
 
-static optionalt<exprt> get_array(
+static std::optional<exprt> get_array(
   const std::function<exprt(const exprt &)> &super_get,
   const namespacet &ns,
   messaget::mstreamt &stream,
   const array_string_exprt &arr,
   const array_poolt &array_pool);
 
-static optionalt<exprt> substitute_array_access(
+static std::optional<exprt> substitute_array_access(
   const index_exprt &index_expr,
   symbol_generatort &symbol_generator,
   const bool left_propagate);
@@ -686,7 +686,7 @@ decision_proceduret::resultt string_refinementt::dec_solve()
     // in the graph.
     const exprt eq_with_char_array_replaced_with_representative_elements =
       replace_expr_copy(symbol_resolve, eq);
-    const optionalt<exprt> new_equation = add_node(
+    const std::optional<exprt> new_equation = add_node(
       dependencies,
       eq_with_char_array_replaced_with_representative_elements,
       generator.array_pool,
@@ -954,7 +954,7 @@ void string_refinementt::add_lemma(
 /// \param array_pool: pool of arrays representing strings
 /// \return an optional expression representing the size of the array that can
 ///         be cast to size_t
-static optionalt<exprt> get_valid_array_size(
+static std::optional<exprt> get_valid_array_size(
   const std::function<exprt(const exprt &)> &super_get,
   const namespacet &ns,
   messaget::mstreamt &stream,
@@ -998,7 +998,7 @@ static optionalt<exprt> get_valid_array_size(
 /// \param arr: expression of type array representing a string
 /// \param array_pool: pool of arrays representing strings
 /// \return an optional array expression or array_of_exprt
-static optionalt<exprt> get_array(
+static std::optional<exprt> get_array(
   const std::function<exprt(const exprt &)> &super_get,
   const namespacet &ns,
   messaget::mstreamt &stream,
@@ -1188,9 +1188,9 @@ static exprt substitute_array_access(
   exprt false_index = index_exprt(if_expr.false_case(), index);
 
   // Substitute recursively in branches of conditional expressions
-  optionalt<exprt> substituted_true_case =
+  std::optional<exprt> substituted_true_case =
     substitute_array_access(true_index, symbol_generator, left_propagate);
-  optionalt<exprt> substituted_false_case =
+  std::optional<exprt> substituted_false_case =
     substitute_array_access(false_index, symbol_generator, left_propagate);
 
   return if_exprt(
@@ -1199,7 +1199,7 @@ static exprt substitute_array_access(
     substituted_false_case ? *substituted_false_case : false_index);
 }
 
-static optionalt<exprt> substitute_array_access(
+static std::optional<exprt> substitute_array_access(
   const index_exprt &index_expr,
   symbol_generatort &symbol_generator,
   const bool left_propagate)
@@ -1238,7 +1238,7 @@ static void substitute_array_access_in_place(
   {
     if(const auto index_expr = expr_try_dynamic_cast<index_exprt>(*it))
     {
-      optionalt<exprt> result =
+      std::optional<exprt> result =
         substitute_array_access(*index_expr, symbol_generator, left_propagate);
 
       // Only perform a write when we have something changed.
@@ -1904,7 +1904,7 @@ exprt string_refinementt::get(const exprt &expr) const
 /// \param message_handler: message handler
 /// \return the witness of the satisfying assignment if one
 ///   exists. If UNSAT, then behaviour is undefined.
-static optionalt<exprt> find_counter_example(
+static std::optional<exprt> find_counter_example(
   const namespacet &ns,
   const exprt &axiom,
   const symbol_exprt &var,
diff --git a/src/solvers/strings/string_refinement_util.cpp b/src/solvers/strings/string_refinement_util.cpp
index e916d280435..db1cc2a57c1 100644
--- a/src/solvers/strings/string_refinement_util.cpp
+++ b/src/solvers/strings/string_refinement_util.cpp
@@ -154,7 +154,7 @@ interval_sparse_arrayt::interval_sparse_arrayt(
   }
 }
 
-optionalt<interval_sparse_arrayt>
+std::optional<interval_sparse_arrayt>
 interval_sparse_arrayt::of_expr(const exprt &expr, const exprt &extra_value)
 {
   if(const auto &array_expr = expr_try_dynamic_cast<array_exprt>(expr))
diff --git a/src/solvers/strings/string_refinement_util.h b/src/solvers/strings/string_refinement_util.h
index adabff4287d..f7531df0233 100644
--- a/src/solvers/strings/string_refinement_util.h
+++ b/src/solvers/strings/string_refinement_util.h
@@ -122,7 +122,7 @@ class interval_sparse_arrayt final : public sparse_arrayt
 
   /// If the expression is an array_exprt or a with_exprt uses the appropriate
   /// constructor, otherwise returns empty optional.
-  static optionalt<interval_sparse_arrayt>
+  static std::optional<interval_sparse_arrayt>
   of_expr(const exprt &expr, const exprt &extra_value);
 
   /// Convert to an array representation, ignores elements at index >= size
diff --git a/src/statement-list/statement_list_parse_tree.h b/src/statement-list/statement_list_parse_tree.h
index 406b4b5acbf..4f5e8efcd1f 100644
--- a/src/statement-list/statement_list_parse_tree.h
+++ b/src/statement-list/statement_list_parse_tree.h
@@ -31,7 +31,7 @@ class statement_list_parse_treet
     /// Representation of the variable, including identifier and type.
     symbol_exprt variable;
     /// Optional default value of the variable.
-    optionalt<exprt> default_value;
+    std::optional<exprt> default_value;
 
     /// Creates a new. variable declaration.
     /// \param symbol: The variable, including type and name.
@@ -58,7 +58,7 @@ class statement_list_parse_treet
   /// and may contain zero or more instructions.
   struct networkt
   {
-    optionalt<std::string> title;
+    std::optional<std::string> title;
     instructionst instructions;
 
     /// Sets the title of the network to a specific value.
diff --git a/src/util/arith_tools.h b/src/util/arith_tools.h
index d5aa518b05d..cfebbce7795 100644
--- a/src/util/arith_tools.h
+++ b/src/util/arith_tools.h
@@ -12,7 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include "invariant.h"
 #include "mp_arith.h"
-#include "optional.h"
 #include "std_expr.h"
 
 #include <limits>
@@ -37,7 +36,7 @@ struct numeric_castt final
 template <>
 struct numeric_castt<mp_integer> final
 {
-  optionalt<mp_integer> operator()(const exprt &expr) const
+  std::optional<mp_integer> operator()(const exprt &expr) const
   {
     if(!expr.is_constant())
       return {};
@@ -45,7 +44,7 @@ struct numeric_castt<mp_integer> final
       return operator()(to_constant_expr(expr));
   }
 
-  optionalt<mp_integer> operator()(const constant_exprt &expr) const
+  std::optional<mp_integer> operator()(const constant_exprt &expr) const
   {
     mp_integer out;
     if(to_integer(expr, out))
@@ -79,7 +78,7 @@ struct numeric_castt<T,
 
 public:
   // Conversion from mp_integer to integral type T
-  optionalt<T> operator()(const mp_integer &mpi) const
+  std::optional<T> operator()(const mp_integer &mpi) const
   {
     static_assert(
       std::numeric_limits<T>::max() <=
@@ -98,7 +97,7 @@ struct numeric_castt<T,
   }
 
   // Conversion from expression
-  optionalt<T> operator()(const exprt &expr) const
+  std::optional<T> operator()(const exprt &expr) const
   {
     if(expr.is_constant())
       return numeric_castt<T>{}(to_constant_expr(expr));
@@ -107,7 +106,7 @@ struct numeric_castt<T,
   }
 
   // Conversion from expression
-  optionalt<T> operator()(const constant_exprt &expr) const
+  std::optional<T> operator()(const constant_exprt &expr) const
   {
     if(auto mpi_opt = numeric_castt<mp_integer>{}(expr))
       return numeric_castt<T>{}(*mpi_opt);
@@ -122,7 +121,7 @@ struct numeric_castt<T,
 /// \return optional integer of type Target if conversion is possible, empty
 ///   optional otherwise.
 template <typename Target>
-optionalt<Target> numeric_cast(const exprt &arg)
+std::optional<Target> numeric_cast(const exprt &arg)
 {
   return numeric_castt<Target>{}(arg);
 }
diff --git a/src/util/c_types.cpp b/src/util/c_types.cpp
index 8e24f1dd825..2b18e322f59 100644
--- a/src/util/c_types.cpp
+++ b/src/util/c_types.cpp
@@ -296,12 +296,12 @@ std::string c_type_as_string(const irep_idt &c_type)
     return "";
 }
 
-optionalt<std::pair<struct_union_typet::componentt, mp_integer>>
+std::optional<std::pair<struct_union_typet::componentt, mp_integer>>
 union_typet::find_widest_union_component(const namespacet &ns) const
 {
   const union_typet::componentst &comps = components();
 
-  optionalt<mp_integer> max_width;
+  std::optional<mp_integer> max_width;
   typet max_comp_type;
   irep_idt max_comp_name;
 
diff --git a/src/util/c_types.h b/src/util/c_types.h
index 00d75bf45d2..7fbad42c800 100644
--- a/src/util/c_types.h
+++ b/src/util/c_types.h
@@ -160,7 +160,7 @@ class union_typet : public struct_union_typet
   /// \param ns: Namespace to resolve tag types.
   /// \return Pair of a componentt pointing to the maximum fixed bit-width
   ///   member of the union type and the bit width of that member.
-  optionalt<std::pair<struct_union_typet::componentt, mp_integer>>
+  std::optional<std::pair<struct_union_typet::componentt, mp_integer>>
   find_widest_union_component(const namespacet &ns) const;
 };
 
diff --git a/src/util/cmdline.cpp b/src/util/cmdline.cpp
index 84530430ae1..a22b5e8b0e7 100644
--- a/src/util/cmdline.cpp
+++ b/src/util/cmdline.cpp
@@ -132,22 +132,22 @@ cmdlinet::get_comma_separated_values(const char *option) const
   return separated_values;
 }
 
-optionalt<std::size_t> cmdlinet::getoptnr(char option) const
+std::optional<std::size_t> cmdlinet::getoptnr(char option) const
 {
   for(std::size_t i=0; i<options.size(); i++)
     if(options[i].optchar==option)
       return i;
 
-  return optionalt<std::size_t>();
+  return std::optional<std::size_t>();
 }
 
-optionalt<std::size_t> cmdlinet::getoptnr(const std::string &option) const
+std::optional<std::size_t> cmdlinet::getoptnr(const std::string &option) const
 {
   for(std::size_t i=0; i<options.size(); i++)
     if(options[i].optstring==option)
       return i;
 
-  return optionalt<std::size_t>();
+  return std::optional<std::size_t>();
 }
 
 bool cmdlinet::parse(int argc, const char **argv, const char *optstring)
@@ -274,7 +274,7 @@ bool cmdlinet::parse_arguments(int argc, const char **argv)
       args.push_back(argv[i]);
     else
     {
-      optionalt<std::size_t> optnr;
+      std::optional<std::size_t> optnr;
 
       if(argv[i][1] != 0 && argv[i][2] == 0)
         optnr = getoptnr(argv[i][1]); // single-letter option -X
diff --git a/src/util/cmdline.h b/src/util/cmdline.h
index b5f68879638..bc624f678e1 100644
--- a/src/util/cmdline.h
+++ b/src/util/cmdline.h
@@ -12,11 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include <limits>
 #include <list>
+#include <optional>
 #include <string>
 #include <vector>
 
-#include "optional.h"
-
 class cmdlinet
 {
 public:
@@ -190,8 +189,8 @@ class cmdlinet
 
   std::vector<optiont> options;
 
-  optionalt<std::size_t> getoptnr(char option) const;
-  optionalt<std::size_t> getoptnr(const std::string &option) const;
+  std::optional<std::size_t> getoptnr(char option) const;
+  std::optional<std::size_t> getoptnr(const std::string &option) const;
 };
 
 #endif // CPROVER_UTIL_CMDLINE_H
diff --git a/src/util/config.h b/src/util/config.h
index 7a58e41918a..0bfedadc627 100644
--- a/src/util/config.h
+++ b/src/util/config.h
@@ -9,11 +9,11 @@ Author: Daniel Kroening, kroening@kroening.com
 #ifndef CPROVER_UTIL_CONFIG_H
 #define CPROVER_UTIL_CONFIG_H
 
-#include <list>
-
 #include "ieee_float.h"
 #include "irep.h"
-#include "optional.h"
+
+#include <list>
+#include <optional>
 
 class cmdlinet;
 class symbol_table_baset;
@@ -287,7 +287,7 @@ class configt
     /// Maximum value of argc, which is operating-systems dependent: Windows
     /// limits the number of characters accepte by CreateProcess, and Unix
     /// systems have sysconf(ARG_MAX).
-    optionalt<mp_integer> max_argc;
+    std::optional<mp_integer> max_argc;
   } ansi_c;
 
   struct cppt
@@ -348,7 +348,7 @@ class configt
   } bv_encoding;
 
   // this is the function to start executing
-  optionalt<std::string> main;
+  std::optional<std::string> main;
 
   void set_arch(const irep_idt &);
 
diff --git a/src/util/dense_integer_map.h b/src/util/dense_integer_map.h
index aafcc920107..8160d80d079 100644
--- a/src/util/dense_integer_map.h
+++ b/src/util/dense_integer_map.h
@@ -17,7 +17,6 @@ Author: Diffblue Ltd
 #include <vector>
 
 #include <util/invariant.h>
-#include <util/optional.h>
 
 /// Identity functor. When we use C++20 this can be replaced with std::identity.
 class identity_functort
@@ -41,10 +40,11 @@ class identity_functort
 ///
 /// The type is optimised for fast lookups at the expense of flexibility.
 /// It makes one compromise on the iterface of std::map / unordered_map: the
-/// iterator refers to a pair<key, optionalt<value>>, where the value optional
-/// will always be defined. This is because the backing store uses optionalt
-/// this way and we don't want to impose the price of copying the key and value
-/// each time we move the iterator just so we have a <const K, V> & to give out.
+/// iterator refers to a pair<key, std::optional<value>>, where the value
+/// optional will always be defined. This is because the backing store uses
+/// std::optional this way and we don't want to impose the price of copying the
+/// key and value each time we move the iterator just so we have a
+/// <const K, V> & to give out.
 ///
 /// Undocumented functions with matching names have the same semantics as
 /// std::map equivalents (including perfect iterator stability, with ordering
@@ -71,8 +71,8 @@ class dense_integer_mapt
 
   // Indicates whether a given position in \ref map's value has been set, and
   // therefore whether our iterators should stop at a given location. We use
-  // this auxiliary structure rather than `pair<K, optionalt<V>>` in \ref map
-  // because this way we can more easily return a std::map-like
+  // this auxiliary structure rather than `pair<K, std::optional<V>>` in
+  // \ref map because this way we can more easily return a std::map-like
   // std::pair<const K, V> & from the iterator.
   std::vector<bool> value_set;
 
diff --git a/src/util/edit_distance.cpp b/src/util/edit_distance.cpp
index b2361ed6ba8..9f0a73c360c 100644
--- a/src/util/edit_distance.cpp
+++ b/src/util/edit_distance.cpp
@@ -54,7 +54,7 @@ bool levenshtein_automatont::matches(const std::string &string) const
   return get_edit_distance(string).has_value();
 }
 
-optionalt<std::size_t>
+std::optional<std::size_t>
 levenshtein_automatont::get_edit_distance(const std::string &string) const
 {
   auto current = nfa.initial_state(0);
diff --git a/src/util/edit_distance.h b/src/util/edit_distance.h
index 2d72586ec79..7d9e1a2a4a9 100644
--- a/src/util/edit_distance.h
+++ b/src/util/edit_distance.h
@@ -15,10 +15,9 @@
 #include "nfa.h"
 
 #include <cstddef>
+#include <optional>
 #include <string>
 
-#include <util/optional.h>
-
 /// Simple automaton that can detect whether a string can be transformed into
 /// another with a limited number of deletions, insertions or substitutions.
 /// Not a very fast implementation, but should be good enough for small strings.
@@ -35,7 +34,7 @@ struct levenshtein_automatont
     std::size_t allowed_errors = 2);
 
   bool matches(const std::string &string) const;
-  optionalt<std::size_t> get_edit_distance(const std::string &string) const;
+  std::optional<std::size_t> get_edit_distance(const std::string &string) const;
 
   void dump_automaton_dot_to(std::ostream &out)
   {
diff --git a/src/util/expr_cast.h b/src/util/expr_cast.h
index 52992f0c5ea..c568692366e 100644
--- a/src/util/expr_cast.h
+++ b/src/util/expr_cast.h
@@ -101,10 +101,10 @@ auto expr_try_dynamic_cast(TExpr &base)
 /// \tparam T: The type to cast the \p base param to.
 /// \tparam TType: The original type to cast from, must be a exprt rvalue.
 /// \param base: A generic \ref exprt rvalue.
-/// \return Cast value in an optionalt<T> or empty if \a base is not an instance
-///         of T.
+/// \return Cast value in an std::optional<T> or empty if \a base is not an
+///         instance of T.
 template <typename T, typename TExpr>
-optionalt<T> expr_try_dynamic_cast(TExpr &&base)
+std::optional<T> expr_try_dynamic_cast(TExpr &&base)
 {
   static_assert(
     std::is_rvalue_reference<decltype(base)>::value,
@@ -118,7 +118,7 @@ optionalt<T> expr_try_dynamic_cast(TExpr &&base)
   static_assert(!std::is_const<TExpr>::value, "Attempted to move from const.");
   if(!can_cast_expr<T>(base))
     return {};
-  optionalt<T> ret{static_cast<T &&>(base)};
+  std::optional<T> ret{static_cast<T &&>(base)};
   validate_expr(*ret);
   return ret;
 }
@@ -153,10 +153,10 @@ auto type_try_dynamic_cast(TType &base) ->
 /// \tparam T: The type to cast the \p base param to.
 /// \tparam TType: The original type to cast from, must be a typet rvalue.
 /// \param base: A generic \ref typet rvalue.
-/// \return Cast value in an optionalt<T> or empty if \a base is not an instance
-///         of T.
+/// \return Cast value in an std::optional<T> or empty if \a base is not an
+///         instance of T.
 template <typename T, typename TType>
-optionalt<T> type_try_dynamic_cast(TType &&base)
+std::optional<T> type_try_dynamic_cast(TType &&base)
 {
   static_assert(
     std::is_rvalue_reference<decltype(base)>::value,
@@ -171,7 +171,7 @@ optionalt<T> type_try_dynamic_cast(TType &&base)
   if(!can_cast_type<T>(base))
     return {};
   TType::check(base);
-  optionalt<T> ret{static_cast<T &&>(base)};
+  std::optional<T> ret{static_cast<T &&>(base)};
   return ret;
 }
 
diff --git a/src/util/expr_initializer.cpp b/src/util/expr_initializer.cpp
index 2cd605253b2..3525b2804e1 100644
--- a/src/util/expr_initializer.cpp
+++ b/src/util/expr_initializer.cpp
@@ -29,7 +29,7 @@ class expr_initializert
   {
   }
 
-  optionalt<exprt> operator()(
+  std::optional<exprt> operator()(
     const typet &type,
     const source_locationt &source_location,
     const exprt &init_expr)
@@ -40,13 +40,13 @@ class expr_initializert
 protected:
   const namespacet &ns;
 
-  optionalt<exprt> expr_initializer_rec(
+  std::optional<exprt> expr_initializer_rec(
     const typet &type,
     const source_locationt &source_location,
     const exprt &init_expr);
 };
 
-optionalt<exprt> expr_initializert::expr_initializer_rec(
+std::optional<exprt> expr_initializert::expr_initializer_rec(
   const typet &type,
   const source_locationt &source_location,
   const exprt &init_expr)
@@ -305,7 +305,7 @@ optionalt<exprt> expr_initializert::expr_initializer_rec(
 /// \param ns: Namespace to perform type symbol/tag lookups.
 /// \return An expression if a constant expression of the input type can be
 ///   built.
-optionalt<exprt> zero_initializer(
+std::optional<exprt> zero_initializer(
   const typet &type,
   const source_locationt &source_location,
   const namespacet &ns)
@@ -321,7 +321,7 @@ optionalt<exprt> zero_initializer(
 /// \param ns: Namespace to perform type symbol/tag lookups.
 /// \return An expression if a non-deterministic expression of the input type
 ///   can be built.
-optionalt<exprt> nondet_initializer(
+std::optional<exprt> nondet_initializer(
   const typet &type,
   const source_locationt &source_location,
   const namespacet &ns)
@@ -337,7 +337,7 @@ optionalt<exprt> nondet_initializer(
 /// \param init_byte_expr: Value to be used for initialization.
 /// \return An expression if a byte-initialized expression of the input type
 ///   can be built.
-optionalt<exprt> expr_initializer(
+std::optional<exprt> expr_initializer(
   const typet &type,
   const source_locationt &source_location,
   const namespacet &ns,
diff --git a/src/util/expr_initializer.h b/src/util/expr_initializer.h
index f9421ef56e5..4a3c8ee67de 100644
--- a/src/util/expr_initializer.h
+++ b/src/util/expr_initializer.h
@@ -12,22 +12,22 @@ Author: Daniel Kroening, kroening@kroening.com
 #ifndef CPROVER_UTIL_EXPR_INITIALIZER_H
 #define CPROVER_UTIL_EXPR_INITIALIZER_H
 
-#include "optional.h"
+#include <optional>
 
 class exprt;
 class namespacet;
 class source_locationt;
 class typet;
 
-optionalt<exprt>
+std::optional<exprt>
 zero_initializer(const typet &, const source_locationt &, const namespacet &);
 
-optionalt<exprt> nondet_initializer(
+std::optional<exprt> nondet_initializer(
   const typet &type,
   const source_locationt &source_location,
   const namespacet &ns);
 
-optionalt<exprt> expr_initializer(
+std::optional<exprt> expr_initializer(
   const typet &type,
   const source_locationt &source_location,
   const namespacet &ns,
diff --git a/src/util/interval_union.cpp b/src/util/interval_union.cpp
index ef342d2fc38..239ac7a161d 100644
--- a/src/util/interval_union.cpp
+++ b/src/util/interval_union.cpp
@@ -149,7 +149,7 @@ bool interval_uniont::is_empty() const
   return intervals.empty();
 }
 
-optionalt<mp_integer> interval_uniont::maximum() const
+std::optional<mp_integer> interval_uniont::maximum() const
 {
   if(intervals.empty())
     return {};
@@ -159,7 +159,7 @@ optionalt<mp_integer> interval_uniont::maximum() const
   return {};
 }
 
-optionalt<mp_integer> interval_uniont::minimum() const
+std::optional<mp_integer> interval_uniont::minimum() const
 {
   if(intervals.empty())
     return {};
@@ -213,7 +213,7 @@ interval_uniont::of_interval(interval_uniont::intervalt interval)
   return result;
 }
 
-optionalt<interval_uniont>
+std::optional<interval_uniont>
 interval_uniont::of_string(const std::string &to_parse)
 {
   const std::regex limits_regex("\\[(-\\d+|\\d*):(-\\d+|\\d*)\\]");
@@ -235,7 +235,7 @@ interval_uniont::of_string(const std::string &to_parse)
   return result;
 }
 
-optionalt<mp_integer> interval_uniont::as_singleton() const
+std::optional<mp_integer> interval_uniont::as_singleton() const
 {
   if(intervals.size() != 1)
     return {};
diff --git a/src/util/interval_union.h b/src/util/interval_union.h
index d4ddf1aee93..ea535e110bd 100644
--- a/src/util/interval_union.h
+++ b/src/util/interval_union.h
@@ -14,7 +14,8 @@ Author: Diffblue Limited
 
 #include <util/interval_template.h>
 #include <util/mp_arith.h>
-#include <util/optional.h>
+
+#include <optional>
 #include <vector>
 
 class exprt;
@@ -54,11 +55,11 @@ class interval_uniont
 
   /// empty optional means either unbounded on the right or empty,
   /// \ref is_empty has to be called to distinguish between the two
-  optionalt<mp_integer> maximum() const;
+  std::optional<mp_integer> maximum() const;
 
   /// empty optional means either unbounded on the left or empty,
   /// \ref is_empty has to be called to distinguish between the two
-  optionalt<mp_integer> minimum() const;
+  std::optional<mp_integer> minimum() const;
 
   /// Convert the set to a string representing a sequence of intervals, each
   /// interval being of the form "[lower:upper]", "[:upper]" if there is no
@@ -69,7 +70,7 @@ class interval_uniont
   /// Parse a string which is a comma `,` separated list of intervals of the
   /// form "[lower1:upper1]", for example: "[-3:-2],[4:5]".
   /// Return an empty optional if the string doesn't match the format.
-  static optionalt<interval_uniont> of_string(const std::string &to_parse);
+  static std::optional<interval_uniont> of_string(const std::string &to_parse);
 
   /// Construct interval union from a single interval
   static interval_uniont of_interval(intervalt interval);
@@ -78,7 +79,7 @@ class interval_uniont
   exprt make_contains_expr(const exprt &e) const;
 
   /// If the set contains only one element, return the value of this element.
-  optionalt<mp_integer> as_singleton() const;
+  std::optional<mp_integer> as_singleton() const;
 
 private:
   /// Non-overlapping intervals stored in order of their lower bound, so that
diff --git a/src/util/lazy.h b/src/util/lazy.h
index 46458200e40..7d1b93a4832 100644
--- a/src/util/lazy.h
+++ b/src/util/lazy.h
@@ -10,7 +10,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com
 #define CPROVER_UTIL_LAZY_H
 
 #include <functional>
-#include <util/optional.h>
+#include <optional>
 
 template <typename valuet>
 class lazyt
@@ -34,7 +34,7 @@ class lazyt
   }
 
 private:
-  optionalt<valuet> value;
+  std::optional<valuet> value;
   std::function<valuet()> evaluation_function;
 
   explicit lazyt(std::function<valuet()> fun)
diff --git a/src/util/lower_byte_operators.cpp b/src/util/lower_byte_operators.cpp
index 37c7fb9ee69..a9dc5e4213f 100644
--- a/src/util/lower_byte_operators.cpp
+++ b/src/util/lower_byte_operators.cpp
@@ -409,8 +409,8 @@ static exprt bv_to_expr(
 static exprt unpack_rec(
   const exprt &src,
   bool little_endian,
-  const optionalt<mp_integer> &offset_bytes,
-  const optionalt<mp_integer> &max_bytes,
+  const std::optional<mp_integer> &offset_bytes,
+  const std::optional<mp_integer> &max_bytes,
   const std::size_t bits_per_byte,
   const namespacet &ns,
   bool unpack_byte_array = false);
@@ -537,11 +537,11 @@ static exprt unpack_array_vector_no_known_bounds(
 /// \return Array expression holding unpacked elements or array comprehension
 static exprt unpack_array_vector(
   const exprt &src,
-  const optionalt<mp_integer> &src_size,
+  const std::optional<mp_integer> &src_size,
   const mp_integer &element_bits,
   bool little_endian,
-  const optionalt<mp_integer> &offset_bytes,
-  const optionalt<mp_integer> &max_bytes,
+  const std::optional<mp_integer> &offset_bytes,
+  const std::optional<mp_integer> &max_bytes,
   const std::size_t bits_per_byte,
   const namespacet &ns)
 {
@@ -562,7 +562,7 @@ static exprt unpack_array_vector(
 
   // refine the number of elements to extract in case the element width is known
   // and a multiple of bytes; otherwise we will expand the entire array/vector
-  optionalt<mp_integer> num_elements = src_size;
+  std::optional<mp_integer> num_elements = src_size;
   if(element_bits > 0 && element_bits % bits_per_byte == 0)
   {
     if(!num_elements.has_value())
@@ -614,10 +614,10 @@ static exprt unpack_array_vector(
     // recursively unpack each element so that we eventually just have an array
     // of bytes left
 
-    const optionalt<mp_integer> element_max_bytes =
+    const std::optional<mp_integer> element_max_bytes =
       max_bytes
         ? std::min(mp_integer{el_bytes}, *max_bytes - byte_operands.size())
-        : optionalt<mp_integer>{};
+        : std::optional<mp_integer>{};
     const std::size_t element_max_bytes_int =
       element_max_bytes ? numeric_cast_v<std::size_t>(*element_max_bytes)
                         : el_bytes;
@@ -655,8 +655,8 @@ static void process_bit_fields(
   std::size_t total_bits,
   exprt::operandst &dest,
   bool little_endian,
-  const optionalt<mp_integer> &offset_bytes,
-  const optionalt<mp_integer> &max_bytes,
+  const std::optional<mp_integer> &offset_bytes,
+  const std::optional<mp_integer> &max_bytes,
   const std::size_t bits_per_byte,
   const namespacet &ns)
 {
@@ -691,17 +691,17 @@ static void process_bit_fields(
 static array_exprt unpack_struct(
   const exprt &src,
   bool little_endian,
-  const optionalt<mp_integer> &offset_bytes,
-  const optionalt<mp_integer> &max_bytes,
+  const std::optional<mp_integer> &offset_bytes,
+  const std::optional<mp_integer> &max_bytes,
   const std::size_t bits_per_byte,
   const namespacet &ns)
 {
   const struct_typet &struct_type = to_struct_type(ns.follow(src.type()));
   const struct_typet::componentst &components = struct_type.components();
 
-  optionalt<mp_integer> offset_in_member;
-  optionalt<mp_integer> max_bytes_left;
-  optionalt<std::pair<exprt::operandst, std::size_t>> bit_fields;
+  std::optional<mp_integer> offset_in_member;
+  std::optional<mp_integer> max_bytes_left;
+  std::optional<std::pair<exprt::operandst, std::size_t>> bit_fields;
 
   mp_integer member_offset_bits = 0;
   exprt::operandst byte_operands;
@@ -895,8 +895,8 @@ static array_exprt unpack_complex(
 static exprt unpack_rec(
   const exprt &src,
   bool little_endian,
-  const optionalt<mp_integer> &offset_bytes,
-  const optionalt<mp_integer> &max_bytes,
+  const std::optional<mp_integer> &offset_bytes,
+  const std::optional<mp_integer> &max_bytes,
   const std::size_t bits_per_byte,
   const namespacet &ns,
   bool unpack_byte_array)
@@ -1102,7 +1102,7 @@ static exprt lower_byte_extract_array_vector(
   const mp_integer &element_bits,
   const namespacet &ns)
 {
-  optionalt<std::size_t> num_elements;
+  std::optional<std::size_t> num_elements;
   if(src.type().id() == ID_array)
     num_elements = numeric_cast<std::size_t>(to_array_type(src.type()).size());
   else
@@ -1176,7 +1176,7 @@ static exprt lower_byte_extract_array_vector(
 /// \param ns: Namespace
 /// \return An expression if the subtype size is known, else `nullopt` so that a
 /// fall-back to more generic code can be used.
-static optionalt<exprt> lower_byte_extract_complex(
+static std::optional<exprt> lower_byte_extract_complex(
   const byte_extract_exprt &src,
   const byte_extract_exprt &unpacked,
   const namespacet &ns)
@@ -1380,8 +1380,8 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
   const exprt &root = unpacked.op();
   const exprt &offset = unpacked.offset();
 
-  optionalt<typet> subtype;
-  optionalt<typet> index_type;
+  std::optional<typet> subtype;
+  std::optional<typet> index_type;
   if(root.type().id() == ID_vector)
   {
     subtype = to_vector_type(root.type()).element_type();
@@ -1464,7 +1464,7 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
 static exprt lower_byte_update(
   const byte_update_exprt &src,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns);
 
 /// Apply a byte update \p src to an array/vector of bytes using the byte-array
@@ -1549,7 +1549,7 @@ static exprt lower_byte_update_byte_array_vector(
   const byte_update_exprt &src,
   const typet &subtype,
   const array_exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   PRECONDITION(
@@ -1765,7 +1765,7 @@ static exprt lower_byte_update_array_vector_non_const(
   const byte_update_exprt &src,
   const typet &subtype,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   // do all arithmetic below using index/offset types - the array theory
@@ -1918,7 +1918,7 @@ static exprt lower_byte_update_single_element(
   const mp_integer &subtype_bits,
   const mp_integer &bits_already_set,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   // We need to take one or more bytes from value_as_byte_array to modify the
@@ -2048,7 +2048,7 @@ static exprt lower_byte_update_single_element(
     new_value,
     src.get_bits_per_byte()};
 
-  optionalt<exprt> update_bound;
+  std::optional<exprt> update_bound;
   if(non_const_update_bound.has_value())
   {
     // The size of the update is not constant, and thus is to be symbolically
@@ -2091,9 +2091,9 @@ static exprt lower_byte_update_single_element(
 static exprt lower_byte_update_array_vector(
   const byte_update_exprt &src,
   const typet &subtype,
-  const optionalt<mp_integer> &subtype_bits,
+  const std::optional<mp_integer> &subtype_bits,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   const bool is_array = src.type().id() == ID_array;
@@ -2176,7 +2176,7 @@ static exprt lower_byte_update_struct(
   const byte_update_exprt &src,
   const struct_typet &struct_type,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   exprt::operandst elements;
@@ -2280,7 +2280,7 @@ static exprt lower_byte_update_union(
   const byte_update_exprt &src,
   const union_typet &union_type,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   const auto widest_member = union_type.find_widest_union_component(ns);
@@ -2311,12 +2311,12 @@ static exprt lower_byte_update_union(
 static exprt lower_byte_update(
   const byte_update_exprt &src,
   const exprt &value_as_byte_array,
-  const optionalt<exprt> &non_const_update_bound,
+  const std::optional<exprt> &non_const_update_bound,
   const namespacet &ns)
 {
   if(src.type().id() == ID_array || src.type().id() == ID_vector)
   {
-    optionalt<typet> subtype;
+    std::optional<typet> subtype;
     if(src.type().id() == ID_vector)
       subtype = to_vector_type(src.type()).element_type();
     else
@@ -2558,7 +2558,7 @@ exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
   // use a "with" expression to encode the update; else update the values in
   // place.
   // 4) Construct a new object.
-  optionalt<exprt> non_const_update_bound;
+  std::optional<exprt> non_const_update_bound;
   // update value, may require extension to full bytes
   exprt update_value = src.value();
   auto update_size_expr_opt = size_of_expr(update_value.type(), ns);
diff --git a/src/util/numbering.h b/src/util/numbering.h
index b12ae04e6f3..d8a9f3325b2 100644
--- a/src/util/numbering.h
+++ b/src/util/numbering.h
@@ -9,12 +9,12 @@ Author: Daniel Kroening, kroening@kroening.com
 #ifndef CPROVER_UTIL_NUMBERING_H
 #define CPROVER_UTIL_NUMBERING_H
 
+#include "invariant.h"
+
+#include <optional>
 #include <unordered_map>
 #include <vector>
 
-#include "invariant.h"
-#include "optional.h"
-
 /// \tparam keyt: The type of keys which will be numbered.
 /// \tparam hasht: The type of hashing functor used to hash keys.
 template <typename keyt, typename hasht = std::hash<keyt>>
@@ -47,7 +47,7 @@ class numberingt final
     return (result.first)->second;
   }
 
-  optionalt<number_type> get_number(const key_type &a) const
+  std::optional<number_type> get_number(const key_type &a) const
   {
     const auto it = numbers_.find(a);
     if(it == numbers_.end())
diff --git a/src/util/optional.h b/src/util/optional.h
deleted file mode 100644
index 5cf349d2971..00000000000
--- a/src/util/optional.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*******************************************************************\
-
-Module: typedef for optional class template. New code should directly
-        use std::optional.
-
-Author: Diffblue Ltd.
-
-\*******************************************************************/
-
-#ifndef CPROVER_UTIL_OPTIONAL_H
-#define CPROVER_UTIL_OPTIONAL_H
-
-#include "deprecate.h"
-
-#include <optional>
-
-template <typename T>
-using optionalt
-#ifndef _WIN32
-  // Visual Studio doesn't support [deprecated] in this place
-  DEPRECATED(SINCE(2023, 11, 17, "directly use std::optional instead")) =
-#else
-  =
-#endif
-    std::optional<T>; // NOLINT template typedef
-
-#endif // CPROVER_UTIL_OPTIONAL_H
diff --git a/src/util/optional_utils.h b/src/util/optional_utils.h
index 6ddbd1cba51..7a8d91c1bf4 100644
--- a/src/util/optional_utils.h
+++ b/src/util/optional_utils.h
@@ -1,6 +1,6 @@
 /*******************************************************************\
 
-Module: functions that are useful with optionalt
+Module: functions that are useful with std::optional
 
 Author: Diffblue Ltd.
 
@@ -9,13 +9,13 @@ Author: Diffblue Ltd.
 #ifndef CPROVER_UTIL_OPTIONAL_UTILS_H
 #define CPROVER_UTIL_OPTIONAL_UTILS_H
 
-#include "optional.h"
+#include <optional>
 
 /// Lookup a key in a map, if found return the associated value,
 /// nullopt otherwise
 template <typename map_like_collectiont, typename keyt>
 auto optional_lookup(const map_like_collectiont &map, const keyt &key)
-  -> optionalt<decltype(map.find(key)->second)>
+  -> std::optional<decltype(map.find(key)->second)>
 {
   auto const it = map.find(key);
   if(it != map.end())
diff --git a/src/util/piped_process.cpp b/src/util/piped_process.cpp
index 30737050007..bd5e8c7031b 100644
--- a/src/util/piped_process.cpp
+++ b/src/util/piped_process.cpp
@@ -90,7 +90,6 @@
 #include "exception_utils.h"
 #include "invariant.h"
 #include "narrow.h"
-#include "optional.h"
 #include "piped_process.h"
 
 #include <cstring> // library for strerror function (on linux)
@@ -448,7 +447,7 @@ piped_processt::statet piped_processt::get_status()
   return process_state;
 }
 
-bool piped_processt::can_receive(optionalt<std::size_t> wait_time)
+bool piped_processt::can_receive(std::optional<std::size_t> wait_time)
 {
   // unwrap the optional argument here
   const int timeout = wait_time ? narrow<int>(*wait_time) : -1;
diff --git a/src/util/piped_process.h b/src/util/piped_process.h
index c95e4b14b21..c270999adb5 100644
--- a/src/util/piped_process.h
+++ b/src/util/piped_process.h
@@ -14,12 +14,11 @@ typedef void *HANDLE;                                    // NOLINT
 #endif
 
 #include "message.h"
-#include "optional.h"
 
 #include <vector>
 
 #define PIPED_PROCESS_INFINITE_TIMEOUT                                         \
-  optionalt<std::size_t>                                                       \
+  std::optional<std::size_t>                                                   \
   {                                                                            \
   }
 
@@ -63,7 +62,7 @@ class piped_processt
   ///        * 0 signifying non-blocking immediate return, and
   ///        * an empty optional representing infinite wait time.
   /// \return true is there is data to read from process, false otherwise
-  bool can_receive(optionalt<std::size_t> wait_time);
+  bool can_receive(std::optional<std::size_t> wait_time);
 
   /// See if this process can receive data from the other process.
   /// Note this calls can_receive(0);
diff --git a/src/util/pointer_offset_size.cpp b/src/util/pointer_offset_size.cpp
index 0c838161b3c..b0c4de893b4 100644
--- a/src/util/pointer_offset_size.cpp
+++ b/src/util/pointer_offset_size.cpp
@@ -22,7 +22,7 @@ Author: Daniel Kroening, kroening@kroening.com
 #include "ssa_expr.h"
 #include "std_expr.h"
 
-optionalt<mp_integer> member_offset(
+std::optional<mp_integer> member_offset(
   const struct_typet &type,
   const irep_idt &member,
   const namespacet &ns)
@@ -63,7 +63,7 @@ optionalt<mp_integer> member_offset(
   return result;
 }
 
-optionalt<mp_integer> member_offset_bits(
+std::optional<mp_integer> member_offset_bits(
   const struct_typet &type,
   const irep_idt &member,
   const namespacet &ns)
@@ -87,7 +87,7 @@ optionalt<mp_integer> member_offset_bits(
 }
 
 /// Compute the size of a type in bytes, rounding up to full bytes
-optionalt<mp_integer>
+std::optional<mp_integer>
 pointer_offset_size(const typet &type, const namespacet &ns)
 {
   auto bits = pointer_offset_bits(type, ns);
@@ -98,7 +98,7 @@ pointer_offset_size(const typet &type, const namespacet &ns)
     return {};
 }
 
-optionalt<mp_integer>
+std::optional<mp_integer>
 pointer_offset_bits(const typet &type, const namespacet &ns)
 {
   if(type.id()==ID_array)
@@ -218,7 +218,7 @@ pointer_offset_bits(const typet &type, const namespacet &ns)
     return {};
 }
 
-optionalt<exprt>
+std::optional<exprt>
 member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
 {
   // need to distinguish structs and unions
@@ -232,7 +232,7 @@ member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
     return {};
 }
 
-optionalt<exprt> member_offset_expr(
+std::optional<exprt> member_offset_expr(
   const struct_typet &type,
   const irep_idt &member,
   const namespacet &ns)
@@ -278,7 +278,7 @@ optionalt<exprt> member_offset_expr(
   return simplify_expr(std::move(result), ns);
 }
 
-optionalt<exprt> size_of_expr(const typet &type, const namespacet &ns)
+std::optional<exprt> size_of_expr(const typet &type, const namespacet &ns)
 {
   if(type.id()==ID_array)
   {
@@ -504,7 +504,7 @@ optionalt<exprt> size_of_expr(const typet &type, const namespacet &ns)
     return {};
 }
 
-optionalt<mp_integer>
+std::optional<mp_integer>
 compute_pointer_offset(const exprt &expr, const namespacet &ns)
 {
   if(expr.id()==ID_symbol)
@@ -566,7 +566,7 @@ compute_pointer_offset(const exprt &expr, const namespacet &ns)
   return {}; // don't know
 }
 
-optionalt<exprt> get_subexpression_at_offset(
+std::optional<exprt> get_subexpression_at_offset(
   const exprt &expr,
   const mp_integer &offset_bytes,
   const typet &target_type_raw,
@@ -689,7 +689,7 @@ optionalt<exprt> get_subexpression_at_offset(
     expr, from_integer(offset_bytes, c_index_type()), target_type_raw);
 }
 
-optionalt<exprt> get_subexpression_at_offset(
+std::optional<exprt> get_subexpression_at_offset(
   const exprt &expr,
   const exprt &offset,
   const typet &target_type,
diff --git a/src/util/pointer_offset_size.h b/src/util/pointer_offset_size.h
index b4ce99dbf73..97107b11b87 100644
--- a/src/util/pointer_offset_size.h
+++ b/src/util/pointer_offset_size.h
@@ -14,7 +14,8 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include "irep.h"
 #include "mp_arith.h"
-#include "optional.h"
+
+#include <optional>
 
 class exprt;
 class namespacet;
@@ -22,41 +23,42 @@ class struct_typet;
 class typet;
 class member_exprt;
 
-optionalt<mp_integer> member_offset(
+std::optional<mp_integer> member_offset(
   const struct_typet &type,
   const irep_idt &member,
   const namespacet &ns);
 
-optionalt<mp_integer> member_offset_bits(
+std::optional<mp_integer> member_offset_bits(
   const struct_typet &type,
   const irep_idt &member,
   const namespacet &ns);
 
-optionalt<mp_integer>
+std::optional<mp_integer>
 pointer_offset_size(const typet &type, const namespacet &ns);
 
-optionalt<mp_integer>
+std::optional<mp_integer>
 pointer_offset_bits(const typet &type, const namespacet &ns);
 
-optionalt<mp_integer>
+std::optional<mp_integer>
 compute_pointer_offset(const exprt &expr, const namespacet &ns);
 
-optionalt<exprt> member_offset_expr(const member_exprt &, const namespacet &ns);
+std::optional<exprt>
+member_offset_expr(const member_exprt &, const namespacet &ns);
 
-optionalt<exprt> member_offset_expr(
+std::optional<exprt> member_offset_expr(
   const struct_typet &type,
   const irep_idt &member,
   const namespacet &ns);
 
-optionalt<exprt> size_of_expr(const typet &type, const namespacet &ns);
+std::optional<exprt> size_of_expr(const typet &type, const namespacet &ns);
 
-optionalt<exprt> get_subexpression_at_offset(
+std::optional<exprt> get_subexpression_at_offset(
   const exprt &expr,
   const mp_integer &offset,
   const typet &target_type,
   const namespacet &ns);
 
-optionalt<exprt> get_subexpression_at_offset(
+std::optional<exprt> get_subexpression_at_offset(
   const exprt &expr,
   const exprt &offset,
   const typet &target_type,
diff --git a/src/util/sharing_map.h b/src/util/sharing_map.h
index a45b693fad7..2727f019223 100644
--- a/src/util/sharing_map.h
+++ b/src/util/sharing_map.h
@@ -16,9 +16,15 @@ Author: Daniel Poetzl
 #  include <iostream>
 #endif
 
+#include "as_const.h"
+#include "irep.h"
+#include "sharing_node.h"
+#include "threeval.h"
+
 #include <functional>
 #include <map>
 #include <memory>
+#include <optional>
 #include <set>
 #include <stack>
 #include <stdexcept>
@@ -27,12 +33,6 @@ Author: Daniel Poetzl
 #include <type_traits>
 #include <vector>
 
-#include "as_const.h"
-#include "irep.h"
-#include "optional.h"
-#include "sharing_node.h"
-#include "threeval.h"
-
 #ifdef SM_INTERNAL_CHECKS
 #  define SM_ASSERT(b) INVARIANT(b, "Sharing map internal invariant")
 #else
@@ -332,8 +332,8 @@ class sharing_mapt
   /// - Best case: O(1)
   ///
   /// \param k: The key of the element to search
-  /// \return optionalt containing a const reference to the value if found
-  optionalt<std::reference_wrapper<const mapped_type>>
+  /// \return std::optional containing a const reference to the value if found
+  std::optional<std::reference_wrapper<const mapped_type>>
   find(const key_type &k) const;
 
   /// Swap with other map
@@ -1448,7 +1448,7 @@ ::update(const key_type &k, std::function<void(mapped_type &)> mutator)
     "method to check if an update is needed beforehand");
 }
 
-SHARING_MAPT2(optionalt<std::reference_wrapper<const, mapped_type>>)::find(
+SHARING_MAPT2(std::optional<std::reference_wrapper<const, mapped_type>>)::find(
   const key_type &k) const
 {
   const nodet *lp = get_leaf_node(k);
@@ -1456,7 +1456,8 @@ SHARING_MAPT2(optionalt<std::reference_wrapper<const, mapped_type>>)::find(
   if(lp == nullptr)
     return std::nullopt;
 
-  return optionalt<std::reference_wrapper<const mapped_type>>(lp->get_value());
+  return std::optional<std::reference_wrapper<const mapped_type>>(
+    lp->get_value());
 }
 
 // static constants
diff --git a/src/util/sharing_node.h b/src/util/sharing_node.h
index 4caf809bb55..601b43b8352 100644
--- a/src/util/sharing_node.h
+++ b/src/util/sharing_node.h
@@ -17,6 +17,7 @@ Author: Daniel Poetzl
 #endif
 
 #include <forward_list>
+#include <functional>
 #include <type_traits>
 
 #ifndef SN_SMALL_MAP
diff --git a/src/util/simplify_expr.cpp b/src/util/simplify_expr.cpp
index 01f969bc74d..6112e4c45fe 100644
--- a/src/util/simplify_expr.cpp
+++ b/src/util/simplify_expr.cpp
@@ -1717,7 +1717,7 @@ simplify_exprt::simplify_byte_extract(const byte_extract_exprt &expr)
 
   // try to simplify byte_extract(byte_update(...))
   auto const bu = expr_try_dynamic_cast<byte_update_exprt>(expr.op());
-  optionalt<mp_integer> update_offset;
+  std::optional<mp_integer> update_offset;
   if(bu)
     update_offset = numeric_cast<mp_integer>(bu->offset());
   if(bu && el_size.has_value() && update_offset.has_value())
@@ -2028,7 +2028,7 @@ simplify_exprt::simplify_byte_extract_preorder(const byte_extract_exprt &expr)
   }
   else
   {
-    optionalt<exprt::operandst> new_operands;
+    std::optional<exprt::operandst> new_operands;
 
     for(std::size_t i = 0; i < expr.operands().size(); ++i)
     {
@@ -2665,7 +2665,7 @@ simplify_exprt::simplify_overflow_result(const overflow_result_exprt &expr)
       {
         if(skip_typecast(sum->op0()) == tc_op1 && sum->operands().size() == 2)
         {
-          optionalt<exprt> offset;
+          std::optional<exprt> offset;
           if(sum->type().id() == ID_pointer)
           {
             offset = std::move(simplify_pointer_offset(
@@ -2711,7 +2711,7 @@ simplify_exprt::simplify_overflow_result(const overflow_result_exprt &expr)
       return unchanged(expr);
 
     // preserve the sizeof type annotation
-    optionalt<typet> c_sizeof_type;
+    std::optional<typet> c_sizeof_type;
     for(const auto &op : expr.operands())
     {
       const typet &sizeof_type =
@@ -2808,7 +2808,7 @@ simplify_exprt::simplify_node_preorder(const exprt &expr)
   }
   else if(expr.has_operands())
   {
-    optionalt<exprt::operandst> new_operands;
+    std::optional<exprt::operandst> new_operands;
 
     for(std::size_t i = 0; i < expr.operands().size(); ++i)
     {
diff --git a/src/util/simplify_expr_array.cpp b/src/util/simplify_expr_array.cpp
index 2d71032069f..f33ace7c29c 100644
--- a/src/util/simplify_expr_array.cpp
+++ b/src/util/simplify_expr_array.cpp
@@ -169,7 +169,7 @@ simplify_exprt::simplify_index(const index_exprt &expr)
 
     if(array.type().id() == ID_array || array.type().id() == ID_vector)
     {
-      optionalt<typet> subtype;
+      std::optional<typet> subtype;
       if(array.type().id() == ID_array)
         subtype = to_array_type(array.type()).element_type();
       else
@@ -215,7 +215,7 @@ simplify_exprt::simplify_index_preorder(const index_exprt &expr)
   }
   else
   {
-    optionalt<exprt::operandst> new_operands;
+    std::optional<exprt::operandst> new_operands;
 
     for(std::size_t i = 0; i < expr.operands().size(); ++i)
     {
diff --git a/src/util/simplify_expr_boolean.cpp b/src/util/simplify_expr_boolean.cpp
index 585b2254f8d..569c91ef837 100644
--- a/src/util/simplify_expr_boolean.cpp
+++ b/src/util/simplify_expr_boolean.cpp
@@ -235,7 +235,7 @@ simplify_exprt::resultt<> simplify_exprt::simplify_boolean(const exprt &expr)
 
     if(may_be_reducible_to_interval)
     {
-      optionalt<symbol_exprt> symbol_opt;
+      std::optional<symbol_exprt> symbol_opt;
       std::set<mp_integer> values;
       for(const exprt &op : new_operands)
       {
diff --git a/src/util/simplify_expr_int.cpp b/src/util/simplify_expr_int.cpp
index 3d132ca47fa..826cf4ae34d 100644
--- a/src/util/simplify_expr_int.cpp
+++ b/src/util/simplify_expr_int.cpp
@@ -177,7 +177,7 @@ simplify_exprt::resultt<> simplify_exprt::simplify_mult(const mult_exprt &expr)
   // true if we have found a constant
   bool constant_found = false;
 
-  optionalt<typet> c_sizeof_type;
+  std::optional<typet> c_sizeof_type;
 
   // scan all the operands
   for(exprt::operandst::iterator it = new_operands.begin();
diff --git a/src/util/simplify_expr_struct.cpp b/src/util/simplify_expr_struct.cpp
index 2e66c929a85..a270d01296f 100644
--- a/src/util/simplify_expr_struct.cpp
+++ b/src/util/simplify_expr_struct.cpp
@@ -221,7 +221,7 @@ simplify_exprt::simplify_member(const member_exprt &expr)
     // type and offset with respect to x.
     if(op_type.id() == ID_struct)
     {
-      optionalt<mp_integer> requested_offset =
+      std::optional<mp_integer> requested_offset =
         member_offset(to_struct_type(op_type), component_name, ns);
       if(requested_offset.has_value())
       {
diff --git a/src/util/simplify_utils.cpp b/src/util/simplify_utils.cpp
index 2e949b8583f..3b61acd4d08 100644
--- a/src/util/simplify_utils.cpp
+++ b/src/util/simplify_utils.cpp
@@ -193,7 +193,7 @@ bool join_operands(exprt &expr)
   return sort_and_join(expr, false);
 }
 
-optionalt<exprt> bits2expr(
+std::optional<exprt> bits2expr(
   const std::string &bits,
   const typet &type,
   bool little_endian,
@@ -410,7 +410,7 @@ optionalt<exprt> bits2expr(
   return {};
 }
 
-optionalt<std::string>
+std::optional<std::string>
 expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
 {
   // extract bits from lowest to highest memory address
@@ -485,7 +485,7 @@ expr2bits(const exprt &expr, bool little_endian, const namespacet &ns)
   return {};
 }
 
-optionalt<std::reference_wrapper<const array_exprt>>
+std::optional<std::reference_wrapper<const array_exprt>>
 try_get_string_data_array(const exprt &content, const namespacet &ns)
 {
   if(content.id() != ID_address_of)
@@ -522,5 +522,5 @@ try_get_string_data_array(const exprt &content, const namespacet &ns)
 
   const auto &char_seq = to_array_expr(symbol_ptr->value);
 
-  return optionalt<std::reference_wrapper<const array_exprt>>(char_seq);
+  return std::optional<std::reference_wrapper<const array_exprt>>(char_seq);
 }
diff --git a/src/util/simplify_utils.h b/src/util/simplify_utils.h
index c65011a2129..d3e40799f87 100644
--- a/src/util/simplify_utils.h
+++ b/src/util/simplify_utils.h
@@ -11,7 +11,6 @@ Author: Daniel Kroening, kroening@kroening.com
 #define CPROVER_UTIL_SIMPLIFY_UTILS_H
 
 #include "expr.h"
-#include "optional.h"
 
 #include <string>
 
@@ -25,13 +24,13 @@ bool join_operands(exprt &expr);
 bool sort_and_join(exprt &expr);
 
 // bit-level conversions
-optionalt<exprt> bits2expr(
+std::optional<exprt> bits2expr(
   const std::string &bits,
   const typet &type,
   bool little_endian,
   const namespacet &ns);
 
-optionalt<std::string>
+std::optional<std::string>
 expr2bits(const exprt &, bool little_endian, const namespacet &ns);
 
 /// Get char sequence from content field of a refined string expression
@@ -46,7 +45,7 @@ expr2bits(const exprt &, bool little_endian, const namespacet &ns);
 /// \return array expression representing the char sequence which forms the
 ///   content of the refined string expression, empty optional if the content
 ///   cannot be determined
-optionalt<std::reference_wrapper<const array_exprt>>
+std::optional<std::reference_wrapper<const array_exprt>>
 try_get_string_data_array(const exprt &content, const namespacet &ns);
 
 #endif // CPROVER_UTIL_SIMPLIFY_UTILS_H
diff --git a/src/util/source_location.cpp b/src/util/source_location.cpp
index 58897b858da..7f93bf4b253 100644
--- a/src/util/source_location.cpp
+++ b/src/util/source_location.cpp
@@ -82,7 +82,7 @@ void source_locationt::merge(const source_locationt &from)
 /// Get a path to the file, including working directory.
 /// \return Full path unless the file name is empty or refers
 ///   to a built-in, in which case {} is returned.
-optionalt<std::string> source_locationt::full_path() const
+std::optional<std::string> source_locationt::full_path() const
 {
   const auto file = id2string(get_file());
 
diff --git a/src/util/source_location.h b/src/util/source_location.h
index 340644fef29..fe99c578fb3 100644
--- a/src/util/source_location.h
+++ b/src/util/source_location.h
@@ -12,8 +12,8 @@ Author: Daniel Kroening, kroening@kroening.com
 
 #include "deprecate.h"
 #include "irep.h"
-#include "optional.h"
 
+#include <optional>
 #include <string>
 
 class source_locationt:public irept
@@ -189,7 +189,7 @@ class source_locationt:public irept
     return static_cast<const source_locationt &>(get_nil_irep());
   }
 
-  optionalt<std::string> full_path() const;
+  std::optional<std::string> full_path() const;
 
   void add_pragma(const irep_idt &pragma)
   {
diff --git a/src/util/std_code.h b/src/util/std_code.h
index fb55e510b09..6cd7f9eddd3 100644
--- a/src/util/std_code.h
+++ b/src/util/std_code.h
@@ -370,7 +370,7 @@ class code_frontend_declt : public codet
   /// or empty in the case where no initialisation is included.
   /// \note: Initial values may be present in the front end but they must be
   ///   separated into a separate assignment when used in a `goto_instructiont`.
-  optionalt<exprt> initial_value() const
+  std::optional<exprt> initial_value() const
   {
     if(operands().size() < 2)
       return {};
@@ -381,7 +381,7 @@ class code_frontend_declt : public codet
   /// variable. Empty optional maybe passed to remove existing initialisation.
   /// \note: Initial values may be present in the front end but they must be
   ///   separated into a separate assignment when used in a `goto_instructiont`.
-  void set_initial_value(optionalt<exprt> initial_value)
+  void set_initial_value(std::optional<exprt> initial_value)
   {
     if(!initial_value)
     {
diff --git a/src/util/std_types.cpp b/src/util/std_types.cpp
index 117c7672ffa..2fc68862ee1 100644
--- a/src/util/std_types.cpp
+++ b/src/util/std_types.cpp
@@ -100,7 +100,8 @@ void struct_typet::add_base(const struct_tag_typet &base)
   bases().push_back(baset(base));
 }
 
-optionalt<struct_typet::baset> struct_typet::get_base(const irep_idt &id) const
+std::optional<struct_typet::baset>
+struct_typet::get_base(const irep_idt &id) const
 {
   for(const auto &b : bases())
   {
diff --git a/src/util/std_types.h b/src/util/std_types.h
index acc03e9e703..37849dce9c1 100644
--- a/src/util/std_types.h
+++ b/src/util/std_types.h
@@ -277,7 +277,7 @@ class struct_typet:public struct_union_typet
   /// Return the base with the given name, if exists.
   /// \param id: The name of the base we are looking for.
   /// \return The base if exists.
-  optionalt<baset> get_base(const irep_idt &id) const;
+  std::optional<baset> get_base(const irep_idt &id) const;
 
   /// Test whether `id` is a base class/struct.
   /// \param id: symbol type name
diff --git a/src/util/string2int.cpp b/src/util/string2int.cpp
index 6cf4bf75b12..02a90120a52 100644
--- a/src/util/string2int.cpp
+++ b/src/util/string2int.cpp
@@ -56,17 +56,19 @@ unsigned long long int unsafe_string2unsignedlonglong(
   return *string2optional<unsigned long long>(str, base);
 }
 
-optionalt<int> string2optional_int(const std::string &str, int base)
+std::optional<int> string2optional_int(const std::string &str, int base)
 {
   return string2optional<int>(str, base);
 }
 
-optionalt<unsigned> string2optional_unsigned(const std::string &str, int base)
+std::optional<unsigned>
+string2optional_unsigned(const std::string &str, int base)
 {
   return string2optional<unsigned>(str, base);
 }
 
-optionalt<std::size_t> string2optional_size_t(const std::string &str, int base)
+std::optional<std::size_t>
+string2optional_size_t(const std::string &str, int base)
 {
   return string2optional<std::size_t>(str, base);
 }
diff --git a/src/util/string2int.h b/src/util/string2int.h
index 0d9d71defe8..cafb137e85b 100644
--- a/src/util/string2int.h
+++ b/src/util/string2int.h
@@ -11,7 +11,8 @@ Author: Michael Tautschnig, michael.tautschnig@cs.ox.ac.uk
 #define CPROVER_UTIL_STRING2INT_H
 
 #include "narrow.h"
-#include "optional.h"
+
+#include <optional>
 #include <string>
 #include <type_traits>
 
@@ -38,18 +39,18 @@ long long unsigned int unsafe_string2unsignedlonglong(
 
 /// Convert string to integer as per stoi, but return nullopt when
 /// stoi would throw
-optionalt<int> string2optional_int(const std::string &, int base = 10);
+std::optional<int> string2optional_int(const std::string &, int base = 10);
 
 /// Convert string to unsigned similar to the stoul or stoull functions,
 /// return nullopt when the conversion fails.
 /// Note: Unlike stoul or stoull negative inputs are disallowed
-optionalt<unsigned>
+std::optional<unsigned>
 string2optional_unsigned(const std::string &, int base = 10);
 
 /// Convert string to size_t similar to the stoul or stoull functions,
 /// return nullopt when the conversion fails.
 /// Note: Unlike stoul or stoull negative inputs are disallowed
-optionalt<std::size_t>
+std::optional<std::size_t>
 string2optional_size_t(const std::string &, int base = 10);
 
 /// convert string to signed long long if T is signed
@@ -86,7 +87,7 @@ auto string2optional_base(const std::string &str, int base) ->
 /// with out_of_range or invalid_argument
 template <typename do_conversiont>
 auto wrap_string_conversion(do_conversiont do_conversion)
-  -> optionalt<decltype(do_conversion())>
+  -> std::optional<decltype(do_conversion())>
 {
   try
   {
@@ -107,7 +108,7 @@ auto wrap_string_conversion(do_conversiont do_conversion)
 ///   (unsigned) long long
 /// does not accept negative inputs when the result type is unsigned
 template <typename T>
-optionalt<T> string2optional(const std::string &str, int base = 10)
+std::optional<T> string2optional(const std::string &str, int base = 10)
 {
   return wrap_string_conversion([&]() {
     return narrow_or_throw_out_of_range<T>(string2optional_base<T>(str, base));
diff --git a/src/util/substitute_symbols.cpp b/src/util/substitute_symbols.cpp
index f28ac87c8e1..95a2fc7ed76 100644
--- a/src/util/substitute_symbols.cpp
+++ b/src/util/substitute_symbols.cpp
@@ -13,7 +13,7 @@ Author: Daniel Kroening, dkr@amazon.com
 
 #include "std_expr.h"
 
-static optionalt<exprt> substitute_symbols_rec(
+static std::optional<exprt> substitute_symbols_rec(
   const std::map<irep_idt, exprt> &substitutions,
   exprt src)
 {
@@ -107,7 +107,7 @@ static optionalt<exprt> substitute_symbols_rec(
     return {};
 }
 
-optionalt<exprt>
+std::optional<exprt>
 substitute_symbols(const std::map<irep_idt, exprt> &substitutions, exprt src)
 {
   return substitute_symbols_rec(substitutions, src);
diff --git a/src/util/substitute_symbols.h b/src/util/substitute_symbols.h
index 0c4ded4b494..dd4e867c2d2 100644
--- a/src/util/substitute_symbols.h
+++ b/src/util/substitute_symbols.h
@@ -13,9 +13,9 @@ Author: Daniel Kroening, dkr@amazon.com
 /// Symbol Substitution
 
 #include "irep.h"
-#include "optional.h"
 
 #include <map>
+#include <optional>
 
 class exprt;
 
@@ -25,7 +25,7 @@ class exprt;
 /// substituted.
 /// \returns expression after substitution,
 /// or {} when no substitution took place
-optionalt<exprt>
+std::optional<exprt>
 substitute_symbols(const std::map<irep_idt, exprt> &substitutions, exprt);
 
 #endif // CPROVER_UTIL_SUBSTITUTE_SYMBOLS_H
diff --git a/src/util/union_find.h b/src/util/union_find.h
index 95a83db9b1b..f38a7e99022 100644
--- a/src/util/union_find.h
+++ b/src/util/union_find.h
@@ -172,8 +172,8 @@ class union_find final
   // are 'a' and 'b' in the same set?
   bool same_set(const T &a, const T &b) const
   {
-    const optionalt<number_type> na = numbers.get_number(a);
-    const optionalt<number_type> nb = numbers.get_number(b);
+    const std::optional<number_type> na = numbers.get_number(a);
+    const std::optional<number_type> nb = numbers.get_number(b);
 
     if(na && nb)
       return uuf.same_set(*na, *nb);
@@ -260,7 +260,7 @@ class union_find final
     uuf.isolate(number(a));
   }
 
-  optionalt<number_type> get_number(const T &a) const
+  std::optional<number_type> get_number(const T &a) const
   {
     return numbers.get_number(a);
   }
diff --git a/unit/analyses/ai/ai.cpp b/unit/analyses/ai/ai.cpp
index 15d50d012e2..5b9ea1dcd46 100644
--- a/unit/analyses/ai/ai.cpp
+++ b/unit/analyses/ai/ai.cpp
@@ -23,7 +23,6 @@ Author: Diffblue Ltd.
 #include <util/arith_tools.h>
 #include <util/config.h>
 #include <util/c_types.h>
-#include <util/optional.h>
 
 /// A very simple analysis that counts executed instructions along a particular
 /// path, taking the max at merge points and saturating at 100 instructions.
@@ -33,8 +32,7 @@ Author: Diffblue Ltd.
 class instruction_counter_domaint : public ai_domain_baset
 {
 public:
-
-  optionalt<unsigned> path_length;
+  std::optional<unsigned> path_length;
 
   void transform(
     const irep_idt &,
diff --git a/unit/ansi-c/c_typecheck_base.cpp b/unit/ansi-c/c_typecheck_base.cpp
index 1723bc30019..a737f27bbe6 100644
--- a/unit/ansi-c/c_typecheck_base.cpp
+++ b/unit/ansi-c/c_typecheck_base.cpp
@@ -28,7 +28,7 @@ class c_typecheck_testt : public c_typecheck_baset
   {
   }
 
-  optionalt<symbol_exprt> test_typecheck_shadow_memory_builtin(
+  std::optional<symbol_exprt> test_typecheck_shadow_memory_builtin(
     const side_effect_expr_function_callt &expr)
   {
     return typecheck_shadow_memory_builtin(expr);
diff --git a/unit/goto-cc/armcc_cmdline.cpp b/unit/goto-cc/armcc_cmdline.cpp
index e9d9ec4f154..f6f0713710f 100644
--- a/unit/goto-cc/armcc_cmdline.cpp
+++ b/unit/goto-cc/armcc_cmdline.cpp
@@ -4,12 +4,11 @@
 
 #include <testing-utils/use_catch.h>
 
-#include <util/optional.h>
-
+#include <optional>
 #include <string>
 #include <vector>
 
-optionalt<std::string>
+std::optional<std::string>
 prefix_in_list(const std::string &option, const std::vector<std::string> &list);
 
 static const std::vector<std::string> test_list{"spam", "eggs", "and", "ham"};
diff --git a/unit/solvers/smt2_incremental/ast/smt_index.cpp b/unit/solvers/smt2_incremental/ast/smt_index.cpp
index bba659b8d70..9892926424c 100644
--- a/unit/solvers/smt2_incremental/ast/smt_index.cpp
+++ b/unit/solvers/smt2_incremental/ast/smt_index.cpp
@@ -1,10 +1,10 @@
 // Author: Diffblue Ltd.
 
-#include <util/optional.h>
-
 #include <solvers/smt2_incremental/ast/smt_index.h>
 #include <testing-utils/use_catch.h>
 
+#include <optional>
+
 TEST_CASE("Test smt_indext.pretty is accessible.", "[core][smt2_incremental]")
 {
   const smt_indext index = smt_numeral_indext{42};
@@ -35,8 +35,8 @@ TEST_CASE("Visiting smt_indext", "[core][smt2_incremental]")
   class : public smt_index_const_downcast_visitort
   {
   public:
-    optionalt<std::size_t> numeral_visited{};
-    optionalt<irep_idt> symbol_visited{};
+    std::optional<std::size_t> numeral_visited{};
+    std::optional<irep_idt> symbol_visited{};
 
     void visit(const smt_numeral_indext &numeral) override
     {
diff --git a/unit/solvers/smt2_incremental/construct_value_expr_from_smt.cpp b/unit/solvers/smt2_incremental/construct_value_expr_from_smt.cpp
index 11a2ec1c2a4..76cedc3115e 100644
--- a/unit/solvers/smt2_incremental/construct_value_expr_from_smt.cpp
+++ b/unit/solvers/smt2_incremental/construct_value_expr_from_smt.cpp
@@ -65,8 +65,8 @@ TEST_CASE("Value expr construction from smt.", "[core][smt2_incremental]")
     make_c_enum_tag_instance_symbol(enum_type_symbol);
   symbol_table.insert(enum_type_symbol);
   symbol_table.insert(enum_tag_value_symbol);
-  optionalt<smt_termt> input_term;
-  optionalt<exprt> expected_result;
+  std::optional<smt_termt> input_term;
+  std::optional<exprt> expected_result;
 
   using rowt = std::pair<smt_termt, exprt>;
 
@@ -143,8 +143,8 @@ TEST_CASE(
     make_c_enum_tag_instance_symbol(enum_type_symbol);
   symbol_table.insert(enum_type_symbol);
   symbol_table.insert(enum_tag_value_symbol);
-  optionalt<smt_termt> input_term;
-  optionalt<typet> input_type;
+  std::optional<smt_termt> input_term;
+  std::optional<typet> input_type;
   std::string invariant_reason;
 
   using rowt = std::tuple<smt_termt, typet, std::string>;
diff --git a/unit/testing-utils/expr_query.h b/unit/testing-utils/expr_query.h
index 84a2d20910b..83c13d683f4 100644
--- a/unit/testing-utils/expr_query.h
+++ b/unit/testing-utils/expr_query.h
@@ -17,8 +17,8 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com
 
 #include <util/expr_cast.h>
 
-/// Wrapper for optionalt<exprt> with useful method for queries to be used in
-/// unit tests.
+/// Wrapper for std::optional<exprt> with useful method for queries to be used
+/// in unit tests.
 template <typename T = exprt>
 class expr_queryt
 {
diff --git a/unit/testing-utils/smt2irep.h b/unit/testing-utils/smt2irep.h
index 8e4eac54ac5..5fd7634ff98 100644
--- a/unit/testing-utils/smt2irep.h
+++ b/unit/testing-utils/smt2irep.h
@@ -3,16 +3,16 @@
 #ifndef CPROVER_TESTING_UTILS_SMT2IREP_H
 #define CPROVER_TESTING_UTILS_SMT2IREP_H
 
-#include <testing-utils/use_catch.h>
-
 #include <util/irep.h>
-#include <util/optional.h>
 
+#include <testing-utils/use_catch.h>
+
+#include <optional>
 #include <string>
 
 struct smt2_parser_test_resultt
 {
-  optionalt<irept> parsed_output;
+  std::optional<irept> parsed_output;
   std::string messages;
 };
 
diff --git a/unit/util/expr_cast/expr_cast.cpp b/unit/util/expr_cast/expr_cast.cpp
index 3272a837480..30204c4059f 100644
--- a/unit/util/expr_cast/expr_cast.cpp
+++ b/unit/util/expr_cast/expr_cast.cpp
@@ -127,7 +127,7 @@ SCENARIO("expr_dynamic_cast",
       "Trying casting from an exprt rvalue reference to a symbol_exprt should "
       "yield a non empty optional.")
     {
-      optionalt<symbol_exprt> result =
+      std::optional<symbol_exprt> result =
         expr_try_dynamic_cast<symbol_exprt>(std::move(expr));
       REQUIRE(result.has_value());
     }
@@ -136,7 +136,8 @@ SCENARIO("expr_dynamic_cast",
       "Trying casting from an exprt rvalue reference to a transt should yield "
       "a empty optional.")
     {
-      optionalt<transt> result = expr_try_dynamic_cast<transt>(std::move(expr));
+      std::optional<transt> result =
+        expr_try_dynamic_cast<transt>(std::move(expr));
       REQUIRE_FALSE(result.has_value());
     }
   }
@@ -242,7 +243,7 @@ SCENARIO("type_dynamic_cast", "[core][utils][expr_cast][type_dynamic_cast]")
       "Trying casting from a typet rvalue reference to a symbol_exprt should "
       "yield a non empty optional.")
     {
-      optionalt<string_typet> result =
+      std::optional<string_typet> result =
         type_try_dynamic_cast<string_typet>(std::move(type));
       REQUIRE(result.has_value());
     }
@@ -251,7 +252,7 @@ SCENARIO("type_dynamic_cast", "[core][utils][expr_cast][type_dynamic_cast]")
       "Trying casting from a typet rvalue reference to a struct_typet should "
       "yield a empty optional.")
     {
-      optionalt<struct_typet> result =
+      std::optional<struct_typet> result =
         type_try_dynamic_cast<struct_typet>(std::move(type));
       REQUIRE_FALSE(result.has_value());
     }
diff --git a/unit/util/json_object.cpp b/unit/util/json_object.cpp
index 23096e1a0ab..74d70147fb3 100644
--- a/unit/util/json_object.cpp
+++ b/unit/util/json_object.cpp
@@ -9,7 +9,6 @@ Author: Diffblue Ltd.
 #include <testing-utils/use_catch.h>
 
 #include <util/json.h>
-#include <util/optional.h>
 #include <util/optional_utils.h>
 #include <util/range.h>
 
@@ -38,13 +37,13 @@ SCENARIO(
           return make_pair(number, json_stringt{number});
         });
 
-      const optionalt<jsont> one = optional_lookup(object, "one");
+      const std::optional<jsont> one = optional_lookup(object, "one");
       REQUIRE(one);
       REQUIRE(one->value == "one");
-      const optionalt<jsont> two = optional_lookup(object, "two");
+      const std::optional<jsont> two = optional_lookup(object, "two");
       REQUIRE(two);
       REQUIRE(two->value == "two");
-      const optionalt<jsont> three = optional_lookup(object, "three");
+      const std::optional<jsont> three = optional_lookup(object, "three");
       REQUIRE(three);
       REQUIRE(three->value == "three");
     }