[v2] Add gdb::nullopt, from C++17's std::nullopt

Message ID 20200519192738.110192-1-cbiesinger@chromium.org
State New
Headers show
Series
  • [v2] Add gdb::nullopt, from C++17's std::nullopt
Related show

Commit Message

From: Christian Biesinger <cbiesinger@google.com>


[Fixes formatting and a compile error, I guess I never compiled the
final version I sent :( Also enables the nullopt unit tests.]

This provides a clearer way to initialize a gdb::optional. E.g.:

  gdb::optional<foo> bar () {
    return gdb::nullopt;
  }

or

  void foo (gdb::optional<bar>) {
  }

  foo (gdb::nullopt);

Also updates all places I could find that use {} or optional() to instead
use nullopt.

gdb/ChangeLog:

2020-05-19  Christian Biesinger  <cbiesinger@google.com>

	* cli/cli-option.c (struct option_def_and_value): Update to use nullopt.
	(parse_option): Likewise.
	* dwarf2/die.h (struct die_info): Likewise.
	* dwarf2/read.c (dw2_expand_symtabs_for_function): Likewise.
	(dw2_debug_names_expand_symtabs_for_function): Likewise.
	(lookup_dwo_id): Likewise.
	* fbsd-tdep.c (fbsd_make_note_desc): Likewise.
	* inf-child.c (inf_child_target::fileio_readlink): Likewise.
	* linux-nat.c (linux_nat_target::fileio_readlink): Likewise.
	* python/python.c (gdbpy_colorize): Likewise.
	* remote.c (remote_target::fileio_readlink): Likewise.
	* solib-aix.c (solib_aix_parse_libraries): Likewise.
	* solib-svr4.c (read_program_header): Likewise.
	(read_program_headers_from_bfd): Likewise.
	* symtab.h (struct general_symbol_info): Likewise.
	* target.c (target_read_alloc_1): Likewise.
	(target_read_stralloc): Likewise.
	(target_get_osdata): Likewise.
	(target_ops::fileio_readlink): Likewise.
	(target_fileio_readlink): Likewise.
	* unittests/optional/assignment/5.cc: Enable nullopt unittests.
	* xml-support.c (xml_fetch_content_from_file): Likewise.
	* xml-tdesc.c (target_fetch_description_xml): Likewise.
	(string_read_description_xml): Likewise.

gdbsupport/ChangeLog:

2020-05-19  Christian Biesinger  <cbiesinger@google.com>

	* gdb_optional.h (struct nullopt_t): Add.
	(nullopt): Add.
	(class optional): Add nullopt_t constructor.

Change-Id: I371f05484a3b85cc6d54a8baead2b4f64e6ee308
---
 gdb/cli/cli-option.c                   | 24 ++++++++++++------------
 gdb/dwarf2/die.h                       |  2 +-
 gdb/dwarf2/read.c                      |  7 ++++---
 gdb/fbsd-tdep.c                        |  2 +-
 gdb/inf-child.c                        |  4 ++--
 gdb/linux-nat.c                        |  2 +-
 gdb/python/python.c                    | 20 ++++++++++----------
 gdb/remote.c                           |  4 ++--
 gdb/solib-aix.c                        |  4 ++--
 gdb/solib-svr4.c                       | 24 ++++++++++++------------
 gdb/symtab.h                           |  3 +--
 gdb/target.c                           | 10 +++++-----
 gdb/unittests/optional/assignment/5.cc | 10 +++-------
 gdb/xml-support.c                      |  4 ++--
 gdb/xml-tdesc.c                        |  7 ++++---
 gdbsupport/gdb_optional.h              | 16 ++++++++++++++++
 16 files changed, 78 insertions(+), 65 deletions(-)

-- 
2.26.2.761.g0e0b3e54be-goog

Comments

Pedro Franco de Carvalho via Gdb-patches June 2, 2020, 8:27 p.m. | #1
Ping? Simon/Pedro, any thoughts?

On Tue, May 19, 2020 at 2:27 PM <cbiesinger@chromium.org> wrote:
>

> From: Christian Biesinger <cbiesinger@google.com>

>

> [Fixes formatting and a compile error, I guess I never compiled the

> final version I sent :( Also enables the nullopt unit tests.]

>

> This provides a clearer way to initialize a gdb::optional. E.g.:

>

>   gdb::optional<foo> bar () {

>     return gdb::nullopt;

>   }

>

> or

>

>   void foo (gdb::optional<bar>) {

>   }

>

>   foo (gdb::nullopt);

>

> Also updates all places I could find that use {} or optional() to instead

> use nullopt.

>

> gdb/ChangeLog:

>

> 2020-05-19  Christian Biesinger  <cbiesinger@google.com>

>

>         * cli/cli-option.c (struct option_def_and_value): Update to use nullopt.

>         (parse_option): Likewise.

>         * dwarf2/die.h (struct die_info): Likewise.

>         * dwarf2/read.c (dw2_expand_symtabs_for_function): Likewise.

>         (dw2_debug_names_expand_symtabs_for_function): Likewise.

>         (lookup_dwo_id): Likewise.

>         * fbsd-tdep.c (fbsd_make_note_desc): Likewise.

>         * inf-child.c (inf_child_target::fileio_readlink): Likewise.

>         * linux-nat.c (linux_nat_target::fileio_readlink): Likewise.

>         * python/python.c (gdbpy_colorize): Likewise.

>         * remote.c (remote_target::fileio_readlink): Likewise.

>         * solib-aix.c (solib_aix_parse_libraries): Likewise.

>         * solib-svr4.c (read_program_header): Likewise.

>         (read_program_headers_from_bfd): Likewise.

>         * symtab.h (struct general_symbol_info): Likewise.

>         * target.c (target_read_alloc_1): Likewise.

>         (target_read_stralloc): Likewise.

>         (target_get_osdata): Likewise.

>         (target_ops::fileio_readlink): Likewise.

>         (target_fileio_readlink): Likewise.

>         * unittests/optional/assignment/5.cc: Enable nullopt unittests.

>         * xml-support.c (xml_fetch_content_from_file): Likewise.

>         * xml-tdesc.c (target_fetch_description_xml): Likewise.

>         (string_read_description_xml): Likewise.

>

> gdbsupport/ChangeLog:

>

> 2020-05-19  Christian Biesinger  <cbiesinger@google.com>

>

>         * gdb_optional.h (struct nullopt_t): Add.

>         (nullopt): Add.

>         (class optional): Add nullopt_t constructor.

>

> Change-Id: I371f05484a3b85cc6d54a8baead2b4f64e6ee308

> ---

>  gdb/cli/cli-option.c                   | 24 ++++++++++++------------

>  gdb/dwarf2/die.h                       |  2 +-

>  gdb/dwarf2/read.c                      |  7 ++++---

>  gdb/fbsd-tdep.c                        |  2 +-

>  gdb/inf-child.c                        |  4 ++--

>  gdb/linux-nat.c                        |  2 +-

>  gdb/python/python.c                    | 20 ++++++++++----------

>  gdb/remote.c                           |  4 ++--

>  gdb/solib-aix.c                        |  4 ++--

>  gdb/solib-svr4.c                       | 24 ++++++++++++------------

>  gdb/symtab.h                           |  3 +--

>  gdb/target.c                           | 10 +++++-----

>  gdb/unittests/optional/assignment/5.cc | 10 +++-------

>  gdb/xml-support.c                      |  4 ++--

>  gdb/xml-tdesc.c                        |  7 ++++---

>  gdbsupport/gdb_optional.h              | 16 ++++++++++++++++

>  16 files changed, 78 insertions(+), 65 deletions(-)

>

> diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c

> index a24eca457d..08457e4e03 100644

> --- a/gdb/cli/cli-option.c

> +++ b/gdb/cli/cli-option.c

> @@ -62,7 +62,7 @@ struct option_def_and_value

>

>    /* Constructor.  */

>    option_def_and_value (const option_def &option_, void *ctx_,

> -                       gdb::optional<option_value> &&value_ = {})

> +                       gdb::optional<option_value> &&value_ = gdb::nullopt)

>      : option (option_),

>        ctx (ctx_),

>        value (std::move (value_))

> @@ -185,15 +185,15 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>               parse_option_completion_info *completion = nullptr)

>  {

>    if (*args == nullptr)

> -    return {};

> +    return gdb::nullopt;

>    else if (**args != '-')

>      {

>        if (have_delimiter)

>         error (_("Unrecognized option at: %s"), *args);

> -      return {};

> +      return gdb::nullopt;

>      }

>    else if (check_for_argument (args, "--"))

> -    return {};

> +    return gdb::nullopt;

>

>    /* Skip the initial '-'.  */

>    const char *arg = *args + 1;

> @@ -216,7 +216,7 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>                       complete_on_options (options_group,

>                                            completion->tracker,

>                                            arg, completion->word);

> -                     return {};

> +                     return gdb::nullopt;

>                     }

>

>                   error (_("Ambiguous option at: -%s"), arg);

> @@ -237,14 +237,14 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>        if (have_delimiter || mode != PROCESS_OPTIONS_UNKNOWN_IS_OPERAND)

>         error (_("Unrecognized option at: %s"), *args);

>

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    if (completion != nullptr && arg[len] == '\0')

>      {

>        complete_on_options (options_group, completion->tracker,

>                            arg, completion->word);

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    *args += 1 + len;

> @@ -347,7 +347,7 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>                 };

>                 complete_on_enum (completion->tracker, all_boolean_enums,

>                                   val_str, val_str);

> -               return {};

> +               return gdb::nullopt;

>               }

>           }

>

> @@ -370,13 +370,13 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>                   (make_unique_xstrdup ("NUMBER"));

>                 completion->tracker.add_completion

>                   (make_unique_xstrdup ("unlimited"));

> -               return {};

> +               return gdb::nullopt;

>               }

>             else if (startswith ("unlimited", *args))

>               {

>                 completion->tracker.add_completion

>                   (make_unique_xstrdup ("unlimited"));

> -               return {};

> +               return gdb::nullopt;

>               }

>           }

>

> @@ -403,7 +403,7 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>                 complete_on_enum (completion->tracker,

>                                   match->enums, *args, *args);

>                 if (completion->tracker.have_completions ())

> -                 return {};

> +                 return gdb::nullopt;

>

>                 /* If we don't have completions, let the

>                    non-completion path throw on invalid enum value

> @@ -448,7 +448,7 @@ parse_option (gdb::array_view<const option_def_group> options_group,

>        gdb_assert_not_reached (_("option type not supported"));

>      }

>

> -  return {};

> +  return gdb::nullopt;

>  }

>

>  /* See cli-option.h.  */

> diff --git a/gdb/dwarf2/die.h b/gdb/dwarf2/die.h

> index 5522ebdf31..9f3a877e73 100644

> --- a/gdb/dwarf2/die.h

> +++ b/gdb/dwarf2/die.h

> @@ -45,7 +45,7 @@ struct die_info

>           /* If both exist, just use the first one.  */

>           return DW_UNSND (&attrs[i]);

>         }

> -    return gdb::optional<ULONGEST> ();

> +    return gdb::nullopt;

>    }

>

>    /* Return range lists base of the compile unit, which, if exists, is

> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c

> index 719051bc5b..13c485b15d 100644

> --- a/gdb/dwarf2/read.c

> +++ b/gdb/dwarf2/read.c

> @@ -3586,7 +3586,8 @@ dw2_expand_symtabs_for_function (struct objfile *objfile,

>    struct dw2_symtab_iterator iter;

>    struct dwarf2_per_cu_data *per_cu;

>

> -  dw2_symtab_iter_init (&iter, dwarf2_per_objfile, {}, VAR_DOMAIN, func_name);

> +  dw2_symtab_iter_init (&iter, dwarf2_per_objfile, gdb::nullopt, VAR_DOMAIN,

> +                       func_name);

>

>    while ((per_cu = dw2_symtab_iter_next (&iter)) != NULL)

>      dw2_instantiate_symtab (per_cu, false);

> @@ -5624,7 +5625,7 @@ dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,

>      {

>        const mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;

>

> -      dw2_debug_names_iterator iter (map, {}, VAR_DOMAIN, func_name);

> +      dw2_debug_names_iterator iter (map, gdb::nullopt, VAR_DOMAIN, func_name);

>

>        struct dwarf2_per_cu_data *per_cu;

>        while ((per_cu = iter.next ()) != NULL)

> @@ -6760,7 +6761,7 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die)

>    struct attribute *attr;

>    attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu);

>    if (attr == nullptr)

> -    return gdb::optional<ULONGEST> ();

> +    return gdb::nullopt;

>    return DW_UNSND (attr);

>  }

>

> diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c

> index acf787c706..b8275814af 100644

> --- a/gdb/fbsd-tdep.c

> +++ b/gdb/fbsd-tdep.c

> @@ -694,7 +694,7 @@ fbsd_make_note_desc (enum target_object object, uint32_t structsize)

>    gdb::optional<gdb::byte_vector> buf =

>      target_read_alloc (current_top_target (), object, NULL);

>    if (!buf || buf->empty ())

> -    return {};

> +    return gdb::nullopt;

>

>    if (structsize == 0)

>      return buf;

> diff --git a/gdb/inf-child.c b/gdb/inf-child.c

> index 4833094889..3420398f82 100644

> --- a/gdb/inf-child.c

> +++ b/gdb/inf-child.c

> @@ -381,13 +381,13 @@ inf_child_target::fileio_readlink (struct inferior *inf, const char *filename,

>    if (len < 0)

>      {

>        *target_errno = host_to_fileio_error (errno);

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    return std::string (buf, len);

>  #else

>    *target_errno = FILEIO_ENOSYS;

> -  return {};

> +  return gdb::nullopt;

>  #endif

>  }

>

> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c

> index 0a2bfdc57d..8de9501639 100644

> --- a/gdb/linux-nat.c

> +++ b/gdb/linux-nat.c

> @@ -4480,7 +4480,7 @@ linux_nat_target::fileio_readlink (struct inferior *inf, const char *filename,

>    if (len < 0)

>      {

>        *target_errno = host_to_fileio_error (errno);

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    return std::string (buf, len);

> diff --git a/gdb/python/python.c b/gdb/python/python.c

> index 67f362b852..c241a09f71 100644

> --- a/gdb/python/python.c

> +++ b/gdb/python/python.c

> @@ -1120,35 +1120,35 @@ static gdb::optional<std::string>

>  gdbpy_colorize (const std::string &filename, const std::string &contents)

>  {

>    if (!gdb_python_initialized)

> -    return {};

> +    return gdb::nullopt;

>

>    gdbpy_enter enter_py (get_current_arch (), current_language);

>

>    if (gdb_python_module == nullptr

>        || !PyObject_HasAttrString (gdb_python_module, "colorize"))

> -    return {};

> +    return gdb::nullopt;

>

>    gdbpy_ref<> hook (PyObject_GetAttrString (gdb_python_module, "colorize"));

>    if (hook == nullptr)

>      {

>        gdbpy_print_stack ();

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    if (!PyCallable_Check (hook.get ()))

> -    return {};

> +    return gdb::nullopt;

>

>    gdbpy_ref<> fname_arg (PyString_FromString (filename.c_str ()));

>    if (fname_arg == nullptr)

>      {

>        gdbpy_print_stack ();

> -      return {};

> +      return gdb::nullopt;

>      }

>    gdbpy_ref<> contents_arg (PyString_FromString (contents.c_str ()));

>    if (contents_arg == nullptr)

>      {

>        gdbpy_print_stack ();

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (),

> @@ -1158,17 +1158,17 @@ gdbpy_colorize (const std::string &filename, const std::string &contents)

>    if (result == nullptr)

>      {

>        gdbpy_print_stack ();

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    if (!gdbpy_is_string (result.get ()))

> -    return {};

> +    return gdb::nullopt;

>

>    gdbpy_ref<> unic = python_string_to_unicode (result.get ());

>    if (unic == nullptr)

>      {

>        gdbpy_print_stack ();

> -      return {};

> +      return gdb::nullopt;

>      }

>    gdbpy_ref<> host_str (PyUnicode_AsEncodedString (unic.get (),

>                                                    host_charset (),

> @@ -1176,7 +1176,7 @@ gdbpy_colorize (const std::string &filename, const std::string &contents)

>    if (host_str == nullptr)

>      {

>        gdbpy_print_stack ();

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    return std::string (PyBytes_AsString (host_str.get ()));

> diff --git a/gdb/remote.c b/gdb/remote.c

> index 312a03c8fb..b910f7e533 100644

> --- a/gdb/remote.c

> +++ b/gdb/remote.c

> @@ -12257,7 +12257,7 @@ remote_target::fileio_readlink (struct inferior *inf, const char *filename,

>    int read_len;

>

>    if (remote_hostio_set_filesystem (inf, remote_errno) != 0)

> -    return {};

> +    return gdb::nullopt;

>

>    remote_buffer_add_string (&p, &left, "vFile:readlink:");

>

> @@ -12269,7 +12269,7 @@ remote_target::fileio_readlink (struct inferior *inf, const char *filename,

>                                     &attachment_len);

>

>    if (len < 0)

> -    return {};

> +    return gdb::nullopt;

>

>    std::string ret (len, '\0');

>

> diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c

> index 125c8960c2..16cf235a20 100644

> --- a/gdb/solib-aix.c

> +++ b/gdb/solib-aix.c

> @@ -108,7 +108,7 @@ solib_aix_parse_libraries (const char *library)

>                   "at compile time"));

>      }

>

> -  return {};

> +  return gdb::nullopt;

>  }

>

>  #else /* HAVE_LIBEXPAT */

> @@ -215,7 +215,7 @@ solib_aix_parse_libraries (const char *library)

>                            library_list_elements, library, &result) == 0)

>      return result;

>

> -  return {};

> +  return gdb::nullopt;

>  }

>

>  #endif /* HAVE_LIBEXPAT */

> diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c

> index 19d1105ae9..6df604cc2f 100644

> --- a/gdb/solib-svr4.c

> +++ b/gdb/solib-svr4.c

> @@ -429,13 +429,13 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>

>    /* Get required auxv elements from target.  */

>    if (target_auxv_search (current_top_target (), AT_PHDR, &at_phdr) <= 0)

> -    return {};

> +    return gdb::nullopt;

>    if (target_auxv_search (current_top_target (), AT_PHENT, &at_phent) <= 0)

> -    return {};

> +    return gdb::nullopt;

>    if (target_auxv_search (current_top_target (), AT_PHNUM, &at_phnum) <= 0)

> -    return {};

> +    return gdb::nullopt;

>    if (!at_phdr || !at_phnum)

> -    return {};

> +    return gdb::nullopt;

>

>    /* Determine ELF architecture type.  */

>    if (at_phent == sizeof (Elf32_External_Phdr))

> @@ -443,7 +443,7 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>    else if (at_phent == sizeof (Elf64_External_Phdr))

>      arch_size = 64;

>    else

> -    return {};

> +    return gdb::nullopt;

>

>    /* Find the requested segment.  */

>    if (type == -1)

> @@ -463,7 +463,7 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>

>           if (target_read_memory (at_phdr + i * sizeof (phdr),

>                                   (gdb_byte *)&phdr, sizeof (phdr)))

> -           return {};

> +           return gdb::nullopt;

>

>           p_type = extract_unsigned_integer ((gdb_byte *) phdr.p_type,

>                                              4, byte_order);

> @@ -480,7 +480,7 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>         }

>

>        if (i == at_phnum)

> -       return {};

> +       return gdb::nullopt;

>

>        /* Retrieve address and size.  */

>        sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr,

> @@ -500,7 +500,7 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>

>           if (target_read_memory (at_phdr + i * sizeof (phdr),

>                                   (gdb_byte *)&phdr, sizeof (phdr)))

> -           return {};

> +           return gdb::nullopt;

>

>           p_type = extract_unsigned_integer ((gdb_byte *) phdr.p_type,

>                                              4, byte_order);

> @@ -517,7 +517,7 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>         }

>

>        if (i == at_phnum)

> -       return {};

> +       return gdb::nullopt;

>

>        /* Retrieve address and size.  */

>        sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr,

> @@ -539,7 +539,7 @@ read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)

>    /* Read in requested program header.  */

>    gdb::byte_vector buf (sect_size);

>    if (target_read_memory (sect_addr, buf.data (), sect_size))

> -    return {};

> +    return gdb::nullopt;

>

>    if (p_arch_size)

>      *p_arch_size = arch_size;

> @@ -2510,12 +2510,12 @@ read_program_headers_from_bfd (bfd *abfd)

>    Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);

>    int phdrs_size = ehdr->e_phnum * ehdr->e_phentsize;

>    if (phdrs_size == 0)

> -    return {};

> +    return gdb::nullopt;

>

>    gdb::byte_vector buf (phdrs_size);

>    if (bfd_seek (abfd, ehdr->e_phoff, SEEK_SET) != 0

>        || bfd_bread (buf.data (), phdrs_size, abfd) != phdrs_size)

> -    return {};

> +    return gdb::nullopt;

>

>    return buf;

>  }

> diff --git a/gdb/symtab.h b/gdb/symtab.h

> index 05e6a311b8..3a1200cfa1 100644

> --- a/gdb/symtab.h

> +++ b/gdb/symtab.h

> @@ -471,8 +471,7 @@ struct general_symbol_info

>       copy_name must be set to true.  */

>    void compute_and_set_names (gdb::string_view linkage_name, bool copy_name,

>                               struct objfile_per_bfd_storage *per_bfd,

> -                             gdb::optional<hashval_t> hash

> -                               = gdb::optional<hashval_t> ());

> +                             gdb::optional<hashval_t> hash = gdb::nullopt);

>

>    /* Name of the symbol.  This is a required field.  Storage for the

>       name is allocated on the objfile_obstack for the associated

> diff --git a/gdb/target.c b/gdb/target.c

> index 6982a806e3..67e26fb46d 100644

> --- a/gdb/target.c

> +++ b/gdb/target.c

> @@ -1781,7 +1781,7 @@ target_read_alloc_1 (struct target_ops *ops, enum target_object object,

>        else if (status != TARGET_XFER_OK)

>         {

>           /* An error occurred.  */

> -         return {};

> +         return gdb::nullopt;

>         }

>

>        buf_pos += xfered_len;

> @@ -1809,7 +1809,7 @@ target_read_stralloc (struct target_ops *ops, enum target_object object,

>      = target_read_alloc_1<char> (ops, object, annex);

>

>    if (!buf)

> -    return {};

> +    return gdb::nullopt;

>

>    if (buf->empty () || buf->back () != '\0')

>      buf->push_back ('\0');

> @@ -2536,7 +2536,7 @@ target_get_osdata (const char *type)

>      t = find_default_run_target ("get OS data");

>

>    if (!t)

> -    return {};

> +    return gdb::nullopt;

>

>    return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);

>  }

> @@ -2772,7 +2772,7 @@ target_ops::fileio_readlink (struct inferior *inf, const char *filename,

>                              int *target_errno)

>  {

>    *target_errno = FILEIO_ENOSYS;

> -  return {};

> +  return gdb::nullopt;

>  }

>

>  /* Helper for target_fileio_open and

> @@ -2984,7 +2984,7 @@ target_fileio_readlink (struct inferior *inf, const char *filename,

>      }

>

>    *target_errno = FILEIO_ENOSYS;

> -  return {};

> +  return gdb::nullopt;

>  }

>

>  /* Like scoped_fd, but specific to target fileio.  */

> diff --git a/gdb/unittests/optional/assignment/5.cc b/gdb/unittests/optional/assignment/5.cc

> index 74d06ae568..4b39b63b54 100644

> --- a/gdb/unittests/optional/assignment/5.cc

> +++ b/gdb/unittests/optional/assignment/5.cc

> @@ -33,23 +33,19 @@ test ()

>  {

>    using O = gdb::optional<value_type>;

>

> -  // Check std::nullopt_t and 'default' (= {}) assignment

> +  // Check gdb::nullopt_t and 'default' (= {}) assignment

>

> -#ifndef GDB_OPTIONAL

>    {

>      O o;

> -    o = std::nullopt;

> +    o = gdb::nullopt;

>      VERIFY( !o );

>    }

> -#endif

>

> -#ifndef GDB_OPTIONAL

>    {

>      O o { gdb::in_place };

> -    o = std::nullopt;

> +    o = gdb::nullopt;

>      VERIFY( !o );

>    }

> -#endif

>

>  #ifndef GDB_OPTIONAL

>    {

> diff --git a/gdb/xml-support.c b/gdb/xml-support.c

> index c906b69fda..5177315be5 100644

> --- a/gdb/xml-support.c

> +++ b/gdb/xml-support.c

> @@ -984,7 +984,7 @@ xml_fetch_content_from_file (const char *filename, void *baton)

>      file = gdb_fopen_cloexec (filename, FOPEN_RB);

>

>    if (file == NULL)

> -    return {};

> +    return gdb::nullopt;

>

>    /* Read in the whole file.  */

>

> @@ -1001,7 +1001,7 @@ xml_fetch_content_from_file (const char *filename, void *baton)

>        || ferror (file.get ()))

>      {

>        warning (_("Read error from \"%s\""), filename);

> -      return {};

> +      return gdb::nullopt;

>      }

>

>    text.back () = '\0';

> diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c

> index 6f108a4e3e..2d47f52b16 100644

> --- a/gdb/xml-tdesc.c

> +++ b/gdb/xml-tdesc.c

> @@ -730,12 +730,12 @@ target_fetch_description_xml (struct target_ops *ops)

>                  "disabled at compile time"));

>      }

>

> -  return {};

> +  return gdb::nullopt;

>  #else

>    gdb::optional<gdb::char_vector>

>      tdesc_str = fetch_available_features_from_target ("target.xml", ops);

>    if (!tdesc_str)

> -    return {};

> +    return gdb::nullopt;

>

>    std::string output;

>    if (!xml_process_xincludes (output,

> @@ -744,7 +744,7 @@ target_fetch_description_xml (struct target_ops *ops)

>                               fetch_available_features_from_target, ops, 0))

>      {

>        warning (_("Could not load XML target description; ignoring"));

> -      return {};

> +      return gdb::nullopt;

>      }

>    return output;

>  #endif

> @@ -758,6 +758,7 @@ string_read_description_xml (const char *xml)

>    return tdesc_parse_xml (xml, [] (const char *href, void *baton)

>      {

>        error (_("xincludes are unsupported with this method"));

> +      // We can't use nullopt here because that messes with the type inference.

>        return gdb::optional<gdb::char_vector> ();

>      }, nullptr);

>  }

> diff --git a/gdbsupport/gdb_optional.h b/gdbsupport/gdb_optional.h

> index 02a87f6ee4..3d8030c754 100644

> --- a/gdbsupport/gdb_optional.h

> +++ b/gdbsupport/gdb_optional.h

> @@ -25,12 +25,18 @@

>  namespace gdb

>  {

>

> +struct nullopt_t

> +{

> +  explicit constexpr nullopt_t (int) {}

> +};

> +

>  struct in_place_t

>  {

>    explicit in_place_t () = default;

>  };

>

>  constexpr gdb::in_place_t in_place {};

> +constexpr nullopt_t nullopt {42};

>

>  /* This class attempts to be a compatible subset of std::optional,

>     which is slated to be available in C++17.  This class optionally

> @@ -55,6 +61,9 @@ class optional

>    constexpr optional ()

>      : m_dummy ()

>    {}

> +  constexpr optional (nullopt_t)

> +    : m_dummy ()

> +  {}

>

>    template<typename... Args>

>    constexpr optional (in_place_t, Args &&... args)

> @@ -93,6 +102,13 @@ class optional

>

>    /* Assignment operators.  */

>

> +  optional &

> +  operator= (nullopt_t)

> +  {

> +    reset ();

> +    return *this;

> +  }

> +

>    optional &

>    operator= (const optional &other)

>    {

> --

> 2.26.2.761.g0e0b3e54be-goog

>
Simon Marchi June 2, 2020, 8:39 p.m. | #2
On 2020-06-02 4:27 p.m., Christian Biesinger wrote:
> Ping? Simon/Pedro, any thoughts?


Looks good to me!

Simon
Pedro Franco de Carvalho via Gdb-patches June 3, 2020, 9:56 a.m. | #3
On 6/2/20 9:27 PM, Christian Biesinger via Gdb-patches wrote:
> Ping? Simon/Pedro, any thoughts?


As I had said on IRC a few days ago:

<palves>      I remember not including std::nullopt in the original gdb::optional patch for some reason.
<palves>      but I don't remember what reason it was.
<palves>      maybe it was an C++17 inline variable or something.
<palves>      if it works, and the tests pass, I'm happy.  ship it.

BTW, was this implementation borrowed from libstdc++; or put another
way, did you take a look at the implementation from libstdc++, see if
there's anything there taking care of some non-obvious issue, that we
should mimic?

Thanks,
Pedro Alves

Patch

diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c
index a24eca457d..08457e4e03 100644
--- a/gdb/cli/cli-option.c
+++ b/gdb/cli/cli-option.c
@@ -62,7 +62,7 @@  struct option_def_and_value
 
   /* Constructor.  */
   option_def_and_value (const option_def &option_, void *ctx_,
-			gdb::optional<option_value> &&value_ = {})
+			gdb::optional<option_value> &&value_ = gdb::nullopt)
     : option (option_),
       ctx (ctx_),
       value (std::move (value_))
@@ -185,15 +185,15 @@  parse_option (gdb::array_view<const option_def_group> options_group,
 	      parse_option_completion_info *completion = nullptr)
 {
   if (*args == nullptr)
-    return {};
+    return gdb::nullopt;
   else if (**args != '-')
     {
       if (have_delimiter)
 	error (_("Unrecognized option at: %s"), *args);
-      return {};
+      return gdb::nullopt;
     }
   else if (check_for_argument (args, "--"))
-    return {};
+    return gdb::nullopt;
 
   /* Skip the initial '-'.  */
   const char *arg = *args + 1;
@@ -216,7 +216,7 @@  parse_option (gdb::array_view<const option_def_group> options_group,
 		      complete_on_options (options_group,
 					   completion->tracker,
 					   arg, completion->word);
-		      return {};
+		      return gdb::nullopt;
 		    }
 
 		  error (_("Ambiguous option at: -%s"), arg);
@@ -237,14 +237,14 @@  parse_option (gdb::array_view<const option_def_group> options_group,
       if (have_delimiter || mode != PROCESS_OPTIONS_UNKNOWN_IS_OPERAND)
 	error (_("Unrecognized option at: %s"), *args);
 
-      return {};
+      return gdb::nullopt;
     }
 
   if (completion != nullptr && arg[len] == '\0')
     {
       complete_on_options (options_group, completion->tracker,
 			   arg, completion->word);
-      return {};
+      return gdb::nullopt;
     }
 
   *args += 1 + len;
@@ -347,7 +347,7 @@  parse_option (gdb::array_view<const option_def_group> options_group,
 		};
 		complete_on_enum (completion->tracker, all_boolean_enums,
 				  val_str, val_str);
-		return {};
+		return gdb::nullopt;
 	      }
 	  }
 
@@ -370,13 +370,13 @@  parse_option (gdb::array_view<const option_def_group> options_group,
 		  (make_unique_xstrdup ("NUMBER"));
 		completion->tracker.add_completion
 		  (make_unique_xstrdup ("unlimited"));
-		return {};
+		return gdb::nullopt;
 	      }
 	    else if (startswith ("unlimited", *args))
 	      {
 		completion->tracker.add_completion
 		  (make_unique_xstrdup ("unlimited"));
-		return {};
+		return gdb::nullopt;
 	      }
 	  }
 
@@ -403,7 +403,7 @@  parse_option (gdb::array_view<const option_def_group> options_group,
 		complete_on_enum (completion->tracker,
 				  match->enums, *args, *args);
 		if (completion->tracker.have_completions ())
-		  return {};
+		  return gdb::nullopt;
 
 		/* If we don't have completions, let the
 		   non-completion path throw on invalid enum value
@@ -448,7 +448,7 @@  parse_option (gdb::array_view<const option_def_group> options_group,
       gdb_assert_not_reached (_("option type not supported"));
     }
 
-  return {};
+  return gdb::nullopt;
 }
 
 /* See cli-option.h.  */
diff --git a/gdb/dwarf2/die.h b/gdb/dwarf2/die.h
index 5522ebdf31..9f3a877e73 100644
--- a/gdb/dwarf2/die.h
+++ b/gdb/dwarf2/die.h
@@ -45,7 +45,7 @@  struct die_info
 	  /* If both exist, just use the first one.  */
 	  return DW_UNSND (&attrs[i]);
 	}
-    return gdb::optional<ULONGEST> ();
+    return gdb::nullopt;
   }
 
   /* Return range lists base of the compile unit, which, if exists, is
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 719051bc5b..13c485b15d 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -3586,7 +3586,8 @@  dw2_expand_symtabs_for_function (struct objfile *objfile,
   struct dw2_symtab_iterator iter;
   struct dwarf2_per_cu_data *per_cu;
 
-  dw2_symtab_iter_init (&iter, dwarf2_per_objfile, {}, VAR_DOMAIN, func_name);
+  dw2_symtab_iter_init (&iter, dwarf2_per_objfile, gdb::nullopt, VAR_DOMAIN,
+			func_name);
 
   while ((per_cu = dw2_symtab_iter_next (&iter)) != NULL)
     dw2_instantiate_symtab (per_cu, false);
@@ -5624,7 +5625,7 @@  dw2_debug_names_expand_symtabs_for_function (struct objfile *objfile,
     {
       const mapped_debug_names &map = *dwarf2_per_objfile->debug_names_table;
 
-      dw2_debug_names_iterator iter (map, {}, VAR_DOMAIN, func_name);
+      dw2_debug_names_iterator iter (map, gdb::nullopt, VAR_DOMAIN, func_name);
 
       struct dwarf2_per_cu_data *per_cu;
       while ((per_cu = iter.next ()) != NULL)
@@ -6760,7 +6761,7 @@  lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
   struct attribute *attr;
   attr = dwarf2_attr (comp_unit_die, DW_AT_GNU_dwo_id, cu);
   if (attr == nullptr)
-    return gdb::optional<ULONGEST> ();
+    return gdb::nullopt;
   return DW_UNSND (attr);
 }
 
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index acf787c706..b8275814af 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -694,7 +694,7 @@  fbsd_make_note_desc (enum target_object object, uint32_t structsize)
   gdb::optional<gdb::byte_vector> buf =
     target_read_alloc (current_top_target (), object, NULL);
   if (!buf || buf->empty ())
-    return {};
+    return gdb::nullopt;
 
   if (structsize == 0)
     return buf;
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 4833094889..3420398f82 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -381,13 +381,13 @@  inf_child_target::fileio_readlink (struct inferior *inf, const char *filename,
   if (len < 0)
     {
       *target_errno = host_to_fileio_error (errno);
-      return {};
+      return gdb::nullopt;
     }
 
   return std::string (buf, len);
 #else
   *target_errno = FILEIO_ENOSYS;
-  return {};
+  return gdb::nullopt;
 #endif
 }
 
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0a2bfdc57d..8de9501639 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4480,7 +4480,7 @@  linux_nat_target::fileio_readlink (struct inferior *inf, const char *filename,
   if (len < 0)
     {
       *target_errno = host_to_fileio_error (errno);
-      return {};
+      return gdb::nullopt;
     }
 
   return std::string (buf, len);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 67f362b852..c241a09f71 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1120,35 +1120,35 @@  static gdb::optional<std::string>
 gdbpy_colorize (const std::string &filename, const std::string &contents)
 {
   if (!gdb_python_initialized)
-    return {};
+    return gdb::nullopt;
 
   gdbpy_enter enter_py (get_current_arch (), current_language);
 
   if (gdb_python_module == nullptr
       || !PyObject_HasAttrString (gdb_python_module, "colorize"))
-    return {};
+    return gdb::nullopt;
 
   gdbpy_ref<> hook (PyObject_GetAttrString (gdb_python_module, "colorize"));
   if (hook == nullptr)
     {
       gdbpy_print_stack ();
-      return {};
+      return gdb::nullopt;
     }
 
   if (!PyCallable_Check (hook.get ()))
-    return {};
+    return gdb::nullopt;
 
   gdbpy_ref<> fname_arg (PyString_FromString (filename.c_str ()));
   if (fname_arg == nullptr)
     {
       gdbpy_print_stack ();
-      return {};
+      return gdb::nullopt;
     }
   gdbpy_ref<> contents_arg (PyString_FromString (contents.c_str ()));
   if (contents_arg == nullptr)
     {
       gdbpy_print_stack ();
-      return {};
+      return gdb::nullopt;
     }
 
   gdbpy_ref<> result (PyObject_CallFunctionObjArgs (hook.get (),
@@ -1158,17 +1158,17 @@  gdbpy_colorize (const std::string &filename, const std::string &contents)
   if (result == nullptr)
     {
       gdbpy_print_stack ();
-      return {};
+      return gdb::nullopt;
     }
 
   if (!gdbpy_is_string (result.get ()))
-    return {};
+    return gdb::nullopt;
 
   gdbpy_ref<> unic = python_string_to_unicode (result.get ());
   if (unic == nullptr)
     {
       gdbpy_print_stack ();
-      return {};
+      return gdb::nullopt;
     }
   gdbpy_ref<> host_str (PyUnicode_AsEncodedString (unic.get (),
 						   host_charset (),
@@ -1176,7 +1176,7 @@  gdbpy_colorize (const std::string &filename, const std::string &contents)
   if (host_str == nullptr)
     {
       gdbpy_print_stack ();
-      return {};
+      return gdb::nullopt;
     }
 
   return std::string (PyBytes_AsString (host_str.get ()));
diff --git a/gdb/remote.c b/gdb/remote.c
index 312a03c8fb..b910f7e533 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -12257,7 +12257,7 @@  remote_target::fileio_readlink (struct inferior *inf, const char *filename,
   int read_len;
 
   if (remote_hostio_set_filesystem (inf, remote_errno) != 0)
-    return {};
+    return gdb::nullopt;
 
   remote_buffer_add_string (&p, &left, "vFile:readlink:");
 
@@ -12269,7 +12269,7 @@  remote_target::fileio_readlink (struct inferior *inf, const char *filename,
 				    &attachment_len);
 
   if (len < 0)
-    return {};
+    return gdb::nullopt;
 
   std::string ret (len, '\0');
 
diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
index 125c8960c2..16cf235a20 100644
--- a/gdb/solib-aix.c
+++ b/gdb/solib-aix.c
@@ -108,7 +108,7 @@  solib_aix_parse_libraries (const char *library)
                  "at compile time"));
     }
 
-  return {};
+  return gdb::nullopt;
 }
 
 #else /* HAVE_LIBEXPAT */
@@ -215,7 +215,7 @@  solib_aix_parse_libraries (const char *library)
 			   library_list_elements, library, &result) == 0)
     return result;
 
-  return {};
+  return gdb::nullopt;
 }
 
 #endif /* HAVE_LIBEXPAT */
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 19d1105ae9..6df604cc2f 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -429,13 +429,13 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
 
   /* Get required auxv elements from target.  */
   if (target_auxv_search (current_top_target (), AT_PHDR, &at_phdr) <= 0)
-    return {};
+    return gdb::nullopt;
   if (target_auxv_search (current_top_target (), AT_PHENT, &at_phent) <= 0)
-    return {};
+    return gdb::nullopt;
   if (target_auxv_search (current_top_target (), AT_PHNUM, &at_phnum) <= 0)
-    return {};
+    return gdb::nullopt;
   if (!at_phdr || !at_phnum)
-    return {};
+    return gdb::nullopt;
 
   /* Determine ELF architecture type.  */
   if (at_phent == sizeof (Elf32_External_Phdr))
@@ -443,7 +443,7 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
   else if (at_phent == sizeof (Elf64_External_Phdr))
     arch_size = 64;
   else
-    return {};
+    return gdb::nullopt;
 
   /* Find the requested segment.  */
   if (type == -1)
@@ -463,7 +463,7 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
 
 	  if (target_read_memory (at_phdr + i * sizeof (phdr),
 				  (gdb_byte *)&phdr, sizeof (phdr)))
-	    return {};
+	    return gdb::nullopt;
 
 	  p_type = extract_unsigned_integer ((gdb_byte *) phdr.p_type,
 					     4, byte_order);
@@ -480,7 +480,7 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
 	}
 
       if (i == at_phnum)
-	return {};
+	return gdb::nullopt;
 
       /* Retrieve address and size.  */
       sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr,
@@ -500,7 +500,7 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
 
 	  if (target_read_memory (at_phdr + i * sizeof (phdr),
 				  (gdb_byte *)&phdr, sizeof (phdr)))
-	    return {};
+	    return gdb::nullopt;
 
 	  p_type = extract_unsigned_integer ((gdb_byte *) phdr.p_type,
 					     4, byte_order);
@@ -517,7 +517,7 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
 	}
 
       if (i == at_phnum)
-	return {};
+	return gdb::nullopt;
 
       /* Retrieve address and size.  */
       sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr,
@@ -539,7 +539,7 @@  read_program_header (int type, int *p_arch_size, CORE_ADDR *base_addr)
   /* Read in requested program header.  */
   gdb::byte_vector buf (sect_size);
   if (target_read_memory (sect_addr, buf.data (), sect_size))
-    return {};
+    return gdb::nullopt;
 
   if (p_arch_size)
     *p_arch_size = arch_size;
@@ -2510,12 +2510,12 @@  read_program_headers_from_bfd (bfd *abfd)
   Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
   int phdrs_size = ehdr->e_phnum * ehdr->e_phentsize;
   if (phdrs_size == 0)
-    return {};
+    return gdb::nullopt;
 
   gdb::byte_vector buf (phdrs_size);
   if (bfd_seek (abfd, ehdr->e_phoff, SEEK_SET) != 0
       || bfd_bread (buf.data (), phdrs_size, abfd) != phdrs_size)
-    return {};
+    return gdb::nullopt;
 
   return buf;
 }
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 05e6a311b8..3a1200cfa1 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -471,8 +471,7 @@  struct general_symbol_info
      copy_name must be set to true.  */
   void compute_and_set_names (gdb::string_view linkage_name, bool copy_name,
 			      struct objfile_per_bfd_storage *per_bfd,
-			      gdb::optional<hashval_t> hash
-			        = gdb::optional<hashval_t> ());
+			      gdb::optional<hashval_t> hash = gdb::nullopt);
 
   /* Name of the symbol.  This is a required field.  Storage for the
      name is allocated on the objfile_obstack for the associated
diff --git a/gdb/target.c b/gdb/target.c
index 6982a806e3..67e26fb46d 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1781,7 +1781,7 @@  target_read_alloc_1 (struct target_ops *ops, enum target_object object,
       else if (status != TARGET_XFER_OK)
 	{
 	  /* An error occurred.  */
-	  return {};
+	  return gdb::nullopt;
 	}
 
       buf_pos += xfered_len;
@@ -1809,7 +1809,7 @@  target_read_stralloc (struct target_ops *ops, enum target_object object,
     = target_read_alloc_1<char> (ops, object, annex);
 
   if (!buf)
-    return {};
+    return gdb::nullopt;
 
   if (buf->empty () || buf->back () != '\0')
     buf->push_back ('\0');
@@ -2536,7 +2536,7 @@  target_get_osdata (const char *type)
     t = find_default_run_target ("get OS data");
 
   if (!t)
-    return {};
+    return gdb::nullopt;
 
   return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
 }
@@ -2772,7 +2772,7 @@  target_ops::fileio_readlink (struct inferior *inf, const char *filename,
 			     int *target_errno)
 {
   *target_errno = FILEIO_ENOSYS;
-  return {};
+  return gdb::nullopt;
 }
 
 /* Helper for target_fileio_open and
@@ -2984,7 +2984,7 @@  target_fileio_readlink (struct inferior *inf, const char *filename,
     }
 
   *target_errno = FILEIO_ENOSYS;
-  return {};
+  return gdb::nullopt;
 }
 
 /* Like scoped_fd, but specific to target fileio.  */
diff --git a/gdb/unittests/optional/assignment/5.cc b/gdb/unittests/optional/assignment/5.cc
index 74d06ae568..4b39b63b54 100644
--- a/gdb/unittests/optional/assignment/5.cc
+++ b/gdb/unittests/optional/assignment/5.cc
@@ -33,23 +33,19 @@  test ()
 {
   using O = gdb::optional<value_type>;
 
-  // Check std::nullopt_t and 'default' (= {}) assignment
+  // Check gdb::nullopt_t and 'default' (= {}) assignment
 
-#ifndef GDB_OPTIONAL
   {
     O o;
-    o = std::nullopt;
+    o = gdb::nullopt;
     VERIFY( !o );
   }
-#endif
 
-#ifndef GDB_OPTIONAL
   {
     O o { gdb::in_place };
-    o = std::nullopt;
+    o = gdb::nullopt;
     VERIFY( !o );
   }
-#endif
 
 #ifndef GDB_OPTIONAL
   {
diff --git a/gdb/xml-support.c b/gdb/xml-support.c
index c906b69fda..5177315be5 100644
--- a/gdb/xml-support.c
+++ b/gdb/xml-support.c
@@ -984,7 +984,7 @@  xml_fetch_content_from_file (const char *filename, void *baton)
     file = gdb_fopen_cloexec (filename, FOPEN_RB);
 
   if (file == NULL)
-    return {};
+    return gdb::nullopt;
 
   /* Read in the whole file.  */
 
@@ -1001,7 +1001,7 @@  xml_fetch_content_from_file (const char *filename, void *baton)
       || ferror (file.get ()))
     {
       warning (_("Read error from \"%s\""), filename);
-      return {};
+      return gdb::nullopt;
     }
 
   text.back () = '\0';
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index 6f108a4e3e..2d47f52b16 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -730,12 +730,12 @@  target_fetch_description_xml (struct target_ops *ops)
 		 "disabled at compile time"));
     }
 
-  return {};
+  return gdb::nullopt;
 #else
   gdb::optional<gdb::char_vector>
     tdesc_str = fetch_available_features_from_target ("target.xml", ops);
   if (!tdesc_str)
-    return {};
+    return gdb::nullopt;
 
   std::string output;
   if (!xml_process_xincludes (output,
@@ -744,7 +744,7 @@  target_fetch_description_xml (struct target_ops *ops)
 			      fetch_available_features_from_target, ops, 0))
     {
       warning (_("Could not load XML target description; ignoring"));
-      return {};
+      return gdb::nullopt;
     }
   return output;
 #endif
@@ -758,6 +758,7 @@  string_read_description_xml (const char *xml)
   return tdesc_parse_xml (xml, [] (const char *href, void *baton)
     {
       error (_("xincludes are unsupported with this method"));
+      // We can't use nullopt here because that messes with the type inference.
       return gdb::optional<gdb::char_vector> ();
     }, nullptr);
 }
diff --git a/gdbsupport/gdb_optional.h b/gdbsupport/gdb_optional.h
index 02a87f6ee4..3d8030c754 100644
--- a/gdbsupport/gdb_optional.h
+++ b/gdbsupport/gdb_optional.h
@@ -25,12 +25,18 @@ 
 namespace gdb
 {
 
+struct nullopt_t
+{
+  explicit constexpr nullopt_t (int) {}
+};
+
 struct in_place_t
 {
   explicit in_place_t () = default;
 };
 
 constexpr gdb::in_place_t in_place {};
+constexpr nullopt_t nullopt {42};
 
 /* This class attempts to be a compatible subset of std::optional,
    which is slated to be available in C++17.  This class optionally
@@ -55,6 +61,9 @@  class optional
   constexpr optional ()
     : m_dummy ()
   {}
+  constexpr optional (nullopt_t)
+    : m_dummy ()
+  {}
 
   template<typename... Args>
   constexpr optional (in_place_t, Args &&... args)
@@ -93,6 +102,13 @@  class optional
 
   /* Assignment operators.  */
 
+  optional &
+  operator= (nullopt_t)
+  {
+    reset ();
+    return *this;
+  }
+
   optional &
   operator= (const optional &other)
   {