/* We've found a component of the name that's an
anonymous namespace. So add symbols in it to the
namespace given by the previous component if there is
- one, or to the global namespace if there isn't. */
+ one, or to the global namespace if there isn't.
+ The declared line of this using directive can be set
+ to 0, this way it is always considered valid. */
std::vector<const char *> excludes;
add_using_directive (compunit->get_local_using_directives (),
- dest, src, NULL, NULL, excludes,
+ dest, src, NULL, NULL, excludes, 0,
1, &objfile->objfile_obstack);
}
/* The "+ 2" is for the "::". */
if (sym.symbol != NULL)
return sym;
+ /* Due to a GCC bug, we need to know the boundaries of the current block
+ to know if a certain using directive is valid. */
+ symtab_and_line boundary_sal = find_pc_line (block->end () - 1, 0);
+
/* Go through the using directives. If any of them add new names to
the namespace we're searching in, see if we can find a match by
applying them. */
-
for (current = block_using (block);
current != NULL;
current = current->next)
{
const char **excludep;
+ /* If the using directive was below the place we are stopped at,
+ do not use this directive. */
+ if (!current->valid_line (boundary_sal.line))
+ continue;
len = strlen (current->import_dest);
directive_match = (search_parents
? (startswith (scope, current->import_dest)
return cu->get_builder ()->get_local_using_directives ();
}
+/* Read the DW_ATTR_decl_line attribute for the given DIE in the
+ given CU. If the format is not recognized or the attribute is
+ not present, set it to 0. */
+
+static unsigned int
+read_decl_line (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *decl_line = dwarf2_attr (die, DW_AT_decl_line, cu);
+ if (decl_line == nullptr)
+ return 0;
+ if (decl_line->form_is_constant ())
+ {
+ LONGEST val = decl_line->constant_value (0);
+ if (0 <= val && val <= UINT_MAX)
+ return (unsigned int) val;
+
+ complaint (_("Declared line for using directive is too large"));
+ return 0;
+ }
+
+ complaint (_("Declared line for using directive is of incorrect format"));
+ return 0;
+}
+
/* Read the import statement specified by the given die and record it. */
static void
import_alias,
imported_declaration,
excludes,
+ read_decl_line (die, cu),
0,
&objfile->objfile_obstack);
}
std::vector<const char *> excludes;
add_using_directive (using_directives (cu),
previous_prefix, type->name (), NULL,
- NULL, excludes, 0, &objfile->objfile_obstack);
+ NULL, excludes,
+ read_decl_line (die, cu),
+ 0, &objfile->objfile_obstack);
}
}
#include "defs.h"
#include "namespace.h"
+#include "frame.h"
/* Add a using directive to USING_DIRECTIVES. If the using directive
in question has already been added, don't add it twice.
const char *alias,
const char *declaration,
const std::vector<const char *> &excludes,
+ unsigned int decl_line,
int copy_names,
struct obstack *obstack)
{
if (ix < excludes.size () || current->excludes[ix] != NULL)
continue;
+ if (decl_line != current->decl_line)
+ continue;
+
/* Parameters exactly match CURRENT. */
return;
}
excludes.size () * sizeof (*newobj->excludes));
newobj->excludes[excludes.size ()] = NULL;
+ newobj->decl_line = decl_line;
+
newobj->next = *using_directives;
*using_directives = newobj;
}
+
+/* See namespace.h. */
+
+bool
+using_direct::valid_line (unsigned int boundary) const
+{
+ try
+ {
+ CORE_ADDR curr_pc = get_frame_pc (get_selected_frame (nullptr));
+ symtab_and_line curr_sal = find_pc_line (curr_pc, 0);
+ return (decl_line <= curr_sal.line)
+ || (decl_line >= boundary);
+ }
+ catch (const gdb_exception &ex)
+ {
+ return true;
+ }
+}
string representing the alias. Otherwise, ALIAS is NULL.
DECLARATION is the name of the imported declaration, if this import
statement represents one. Otherwise DECLARATION is NULL and this
- import statement represents a namespace.
+ import statement represents a namespace. DECL_LINE is the line
+ where the using directive is written in the source code.
C++: using namespace A;
Fortran: use A
struct using_direct *next;
+ /* The line where the using directive was declared on the source file.
+ This is used to check if the using directive is already active at the
+ point where the inferior is stopped. */
+ unsigned int decl_line;
+
/* Used during import search to temporarily mark this node as
searched. */
int searched;
/* USING_DIRECT has variable allocation size according to the number of
EXCLUDES entries, the last entry is NULL. */
const char *excludes[1];
+
+ /* Returns true if the using_direcive USING_DIR is valid in CURR_LINE.
+ Because current GCC (at least version 12.2) sets the decl_line as
+ the last line in the current block, we need to take this into
+ consideration when checking the validity, by comparing it to
+ BOUNDARY, the last line of the current block. */
+ bool valid_line (unsigned int boundary) const;
};
extern void add_using_directive (struct using_direct **using_directives,
const char *alias,
const char *declaration,
const std::vector<const char *> &excludes,
+ const unsigned int decl_line,
int copy_names,
struct obstack *obstack);
int marker10 ()
{
+ int y = 1; // marker10 stop
using namespace M;
- int y = x + 1; // marker10 stop
+ y += x;
using namespace N;
return y;
}
if { [test_compiler_info {gcc-[0-3]-*}] ||
[test_compiler_info {gcc-4-[0-3]-*}]} {
- setup_xfail *-*-*
+ return
}
-# Assert that M::x is printed and not N::x
-gdb_test "print x" "= 911" "print x (from M::x)"
+gdb_test_multiple "print x" "print x, before using statement" {
+ -re -wrap "No symbol .x. in current context.*" {
+ pass $gdb_test_name
+ }
+ -re -wrap "= 911.*" {
+ # GCC doesn't properly set the decl_line for namespaces, so GDB believes
+ # that the "using namespace M" line has already passed at this point.
+ xfail $gdb_test_name
+ }
+}
+gdb_test "next" ".*" "using namespace M"
+gdb_test "print x" "= 911" "print x, only using M"