diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index b2c6baf4432..a8ad11b3468 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -36,6 +36,7 @@ struct symtab; #include "displaced-stepping.h" #include "gdbsupport/intrusive_list.h" #include "thread-fsm.h" +#include "language.h" struct inferior; struct process_stratum_target; @@ -904,7 +905,7 @@ private: /* Save/restore the language as well, because selecting a frame changes the current language to the frame's language if "set language auto". */ - enum language m_lang; + scoped_restore_current_language m_lang; }; /* Returns a pointer into the thread_info corresponding to diff --git a/gdb/language.c b/gdb/language.c index 12a953eaa96..3fbd735a697 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -80,6 +80,7 @@ enum case_sensitivity case_sensitivity = case_sensitive_on; /* The current language and language_mode (see language.h). */ static const struct language_defn *global_current_language; +static lazily_set_language_ftype *lazy_language_setter; enum language_mode language_mode = language_mode_auto; /* See language.h. */ @@ -87,9 +88,41 @@ enum language_mode language_mode = language_mode_auto; const struct language_defn * get_current_language () { + if (lazy_language_setter != nullptr) + { + /* Avoid recursive calls -- set_language refers to + current_language. */ + lazily_set_language_ftype *call = lazy_language_setter; + lazy_language_setter = nullptr; + call (); + } return global_current_language; } +void +lazily_set_language (lazily_set_language_ftype *fun) +{ + lazy_language_setter = fun; +} + +scoped_restore_current_language::scoped_restore_current_language () + : m_lang (global_current_language), + m_fun (lazy_language_setter) +{ +} + +scoped_restore_current_language::~scoped_restore_current_language () +{ + /* If both are NULL, then that means dont_restore was called. */ + if (m_lang != nullptr || m_fun != nullptr) + { + global_current_language = m_lang; + lazy_language_setter = m_fun; + if (lazy_language_setter == nullptr) + set_range_case (); + } +} + /* The language that the user expects to be typing in (the language of main(), or the last language we notified them about, or C). */ @@ -185,6 +218,7 @@ set_language (const char *language) /* Found it! Go into manual mode, and use this language. */ language_mode = language_mode_manual; + lazy_language_setter = nullptr; global_current_language = lang; set_range_case (); expected_language = lang; @@ -372,6 +406,7 @@ set_range_case (void) void set_language (enum language lang) { + lazy_language_setter = nullptr; global_current_language = language_def (lang); set_range_case (); } diff --git a/gdb/language.h b/gdb/language.h index 6ff6f5eb95f..6cbcd119dac 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -787,6 +787,10 @@ extern void language_info (); extern void set_language (enum language lang); +typedef void lazily_set_language_ftype (); +extern void lazily_set_language (lazily_set_language_ftype *fun); + + /* Test a character to decide whether it can be printed in literal form or needs to be printed in another representation. For example, in C the literal form of the character with octal value 141 is 'a' @@ -837,14 +841,14 @@ class scoped_restore_current_language { public: - explicit scoped_restore_current_language () - : m_lang (current_language->la_language) - { - } + scoped_restore_current_language (); + ~scoped_restore_current_language (); - ~scoped_restore_current_language () + scoped_restore_current_language (scoped_restore_current_language &&other) { - set_language (m_lang); + m_lang = other.m_lang; + m_fun = other.m_fun; + other.dont_restore (); } scoped_restore_current_language (const scoped_restore_current_language &) @@ -852,9 +856,18 @@ public: scoped_restore_current_language &operator= (const scoped_restore_current_language &) = delete; + /* Cancel restoring on scope exit. */ + void dont_restore () + { + /* This is implemented using a sentinel value. */ + m_lang = nullptr; + m_fun = nullptr; + } + private: - enum language m_lang; + const language_defn *m_lang; + lazily_set_language_ftype *m_fun; }; /* If language_mode is language_mode_auto, diff --git a/gdb/symfile.c b/gdb/symfile.c index d218dfe7c6d..bdcc27e7ee5 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -1684,13 +1684,11 @@ symbol_file_command (const char *args, int from_tty) } } -/* Set the initial language. */ +/* Lazily set the initial language. */ -void -set_initial_language (void) +static void +set_initial_language_callback () { - if (language_mode == language_mode_manual) - return; enum language lang = main_language (); /* Make C the default language. */ enum language default_lang = language_c; @@ -1715,6 +1713,16 @@ set_initial_language (void) expected_language = current_language; /* Don't warn the user. */ } +/* Set the initial language. */ + +void +set_initial_language (void) +{ + if (language_mode == language_mode_manual) + return; + lazily_set_language (set_initial_language_callback); +} + /* Open the file specified by NAME and hand it off to BFD for preliminary analysis. Return a newly initialized bfd *, which includes a newly malloc'd` copy of NAME (tilde-expanded and made diff --git a/gdb/thread.c b/gdb/thread.c index bd3fe85f3b9..f03a60c4d01 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1438,13 +1438,13 @@ scoped_restore_current_thread::restore () && target_has_stack () && target_has_memory ()) restore_selected_frame (m_selected_frame_id, m_selected_frame_level); - - set_language (m_lang); } scoped_restore_current_thread::~scoped_restore_current_thread () { - if (!m_dont_restore) + if (m_dont_restore) + m_lang.dont_restore (); + else restore (); } @@ -1452,8 +1452,6 @@ scoped_restore_current_thread::scoped_restore_current_thread () { m_inf = inferior_ref::new_reference (current_inferior ()); - m_lang = current_language->la_language; - if (inferior_ptid != null_ptid) { m_thread = thread_info_ref::new_reference (inferior_thread ());