This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH][C++] Fix PR29433, make C++ use a lot less time/memory
- From: Michael Matz <matz at suse dot de>
- To: Mark Mitchell <mark at codesourcery dot com>
- Cc: Daniel Jacobowitz <drow at false dot org>, Richard Guenther <rguenther at suse dot de>, Gabriel Dos Reis <gdr at cs dot tamu dot edu>, gcc-patches at gcc dot gnu dot org
- Date: Wed, 21 Feb 2007 16:45:47 +0100 (CET)
- Subject: Re: [PATCH][C++] Fix PR29433, make C++ use a lot less time/memory
- References: <20061211155733.GA2660@nevyn.them.org> <Pine.LNX.4.64.0612111658590.29962@wotan.suse.de> <20061211174548.GA7094@nevyn.them.org> <Pine.LNX.4.64.0612121519200.29962@wotan.suse.de> <20061212150652.GA18750@nevyn.them.org> <Pine.LNX.4.64.0612121723070.29962@wotan.suse.de> <457EF130.5040902@codesourcery.com> <Pine.LNX.4.64.0612131535100.29962@wotan.suse.de> <4580405A.4000109@codesourcery.com> <Pine.LNX.4.64.0702201500170.25448@wotan.suse.de> <20070220143731.GA8544@caradoc.them.org> <Pine.LNX.4.64.0702201602540.25448@wotan.suse.de> <45DB898E.8080401@codesourcery.com>
Hi,
On Tue, 20 Feb 2007, Mark Mitchell wrote:
> > N1::TA<N1::A>
>
> I spotted the same issue as Daniel. I think that you do need to fix
> this, buy threading a flag down through the diagnostic routines to cause
> it to omit the qualifier on the (outermost) declarator.
Like the patch below. It introduces TFF_NO_OUTER_SCOPE as formatting
flag, and uses it in the new cxx_dwarf_name langhook. I tried to find all
relevant (for dwarf) dumps of scope on the outermost declarator. There
are some more uses of pp_cxx_colon_colon() in the diagnostics but they
aren't at top-level constructs anymore (I believe).
Anyway, now the differences between current trunk and patched trunk look
like so:
- .string "basic_streambuf<char,std::char_traits<char> >"
+ .string "basic_streambuf<char, std::char_traits<char> >"
- .string "list<QString,std::allocator<QString> >"
+ .string "list<QString, std::allocator<QString> >"
So, it's just spacing.
I've also checked the gdb testsuite again with that patch, and there are
14 failures less. Compared to gdb testsuite with unpatched trunk there's
only one regression where it expected something different for a tagless
struct:
ptype v_tagless
type = struct <anonymous struct> {
int one;
int two;
}
(gdb) FAIL: gdb.cp/inherit.exp: ptype variable of type tagless struct
It expected this type:
ptype v_tagless
type = struct ._1 {
int one;
int two;
}
(gdb) PASS: gdb.cp/inherit.exp: ptype variable of type tagless struct
Note, though that such problems also exist without the patch (compared
e.g. to what is generated with gcc 4.1). E.g. this test in gdb fails with
unpatched and patched trunk:
(unpatched gcc)
ptype g_anon_union
type = struct class_with_anon_union {
int one;
class_with_anon_union::._0;
}
(gdb) FAIL: gdb.cp/inherit.exp: print type of anonymous union //
unrecognized line type 1: class_with_anon_union::._0;
(patched gcc)
ptype g_anon_union
type = struct class_with_anon_union {
int one;
class_with_anon_union::<anonymous union>;
}
(gdb) FAIL: gdb.cp/inherit.exp: print type of anonymous union //
unrecognized line type 1: class_with_anon_union::<anonymous union>;
As you can see it merely differs in the "anon" tag. This is the only
difference between gdb results for unpatched and patch gcc, so I think
we're converging to a short term solution (longer term I'd like to emit
the suggested explicit template structure in dwarf).
The patch below is currently in testing. What do people think?
Ciao,
Michael.
* dwarf2out.c (add_AT_string): Call ggc_strdup once per string.
(type_tag): Use lang_hooks.dwarf_name instead of DECL_NAME.
* cp-tree.h (TFF_NO_OUTER_SCOPE): New formatting flag.
* error.c (dump_aggr_type, dump_simple_decl, dump_decl,
dump_function_decl): Guard emitting outer scopes by new flag.
* cp-lang.c (cxx_dwarf_name): New function.
(LANG_HOOKS_DWARF_NAME): Define to cxx_dwarf_name.
* pt.c (classtype_mangled_name, mangle_class_name_for_template):
Remove functions.
(push_template_decl_real, lookup_template_class): Remove calls
to above functions.
Index: dwarf2out.c
===================================================================
--- dwarf2out.c (revision 121950)
+++ dwarf2out.c (working copy)
@@ -5039,9 +5073,15 @@ add_AT_string (dw_die_ref die, enum dwar
slot = htab_find_slot_with_hash (debug_str_hash, str,
htab_hash_string (str), INSERT);
if (*slot == NULL)
- *slot = ggc_alloc_cleared (sizeof (struct indirect_string_node));
- node = (struct indirect_string_node *) *slot;
- node->str = ggc_strdup (str);
+ {
+ node = (struct indirect_string_node *)
+ ggc_alloc_cleared (sizeof (struct indirect_string_node));
+ node->str = ggc_strdup (str);
+ *slot = node;
+ }
+ else
+ node = (struct indirect_string_node *) *slot;
+
node->refcount++;
attr.dw_attr = attr_kind;
@@ -11221,10 +11261,17 @@ type_tag (tree type)
involved. */
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ! DECL_IGNORED_P (TYPE_NAME (type)))
- t = DECL_NAME (TYPE_NAME (type));
+ {
+ /* We want to be extra verbose. Don't call dwarf_name if
+ DECL_NAME isn't set. The default hook for decl_printable_name
+ doesn't like that, and in this context it's correct to return
+ 0, instead of "<anonymous>" or the like. */
+ if (DECL_NAME (TYPE_NAME (type)))
+ name = lang_hooks.dwarf_name (TYPE_NAME (type), 2);
+ }
/* Now get the name as a string, or invent one. */
- if (t != 0)
+ if (!name && t != 0)
name = IDENTIFIER_POINTER (t);
}
Index: cp/error.c
===================================================================
--- cp/error.c (revision 121950)
+++ cp/error.c (working copy)
@@ -445,7 +445,10 @@ dump_aggr_type (tree t, int flags)
&& TYPE_LANG_SPECIFIC (t) && CLASSTYPE_TEMPLATE_INFO (t)
&& (TREE_CODE (CLASSTYPE_TI_TEMPLATE (t)) != TEMPLATE_DECL
|| PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)));
- dump_scope (CP_DECL_CONTEXT (name), flags | TFF_SCOPE);
+
+ if (! (flags & TFF_NO_OUTER_SCOPE))
+ dump_scope (CP_DECL_CONTEXT (name), flags | TFF_SCOPE);
+ flags &= ~TFF_NO_OUTER_SCOPE;
if (tmplate)
{
/* Because the template names are mangled, we have to locate
@@ -695,11 +698,14 @@ dump_simple_decl (tree t, tree type, int
{
if (flags & TFF_DECL_SPECIFIERS)
{
- dump_type_prefix (type, flags);
+ dump_type_prefix (type, flags & ~TFF_NO_OUTER_SCOPE);
pp_maybe_space (cxx_pp);
}
- if (!DECL_INITIAL (t) || TREE_CODE (DECL_INITIAL (t)) != TEMPLATE_PARM_INDEX)
+ if (! (flags & TFF_NO_OUTER_SCOPE)
+ && (!DECL_INITIAL (t)
+ || TREE_CODE (DECL_INITIAL (t)) != TEMPLATE_PARM_INDEX))
dump_scope (CP_DECL_CONTEXT (t), flags);
+ flags &= ~TFF_NO_OUTER_SCOPE;
if (DECL_NAME (t))
dump_decl (DECL_NAME (t), flags);
else
@@ -761,7 +767,9 @@ dump_decl (tree t, int flags)
pp_cxx_declaration (cxx_pp, t);
else
{
- dump_scope (CP_DECL_CONTEXT (t), flags);
+ if (! (flags & TFF_NO_OUTER_SCOPE))
+ dump_scope (CP_DECL_CONTEXT (t), flags);
+ flags &= ~TFF_NO_OUTER_SCOPE;
if (DECL_NAME (t) == NULL_TREE)
pp_identifier (cxx_pp, "<unnamed>");
else
@@ -996,7 +1004,9 @@ dump_function_decl (tree t, int flags)
tree template_args = NULL_TREE;
tree template_parms = NULL_TREE;
int show_return = flags & TFF_RETURN_TYPE || flags & TFF_DECL_SPECIFIERS;
+ int do_outer_scope = ! (flags & TFF_NO_OUTER_SCOPE);
+ flags &= ~TFF_NO_OUTER_SCOPE;
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
@@ -1038,7 +1048,9 @@ dump_function_decl (tree t, int flags)
dump_type_prefix (TREE_TYPE (fntype), flags);
/* Print the function name. */
- if (cname)
+ if (!do_outer_scope)
+ /* Nothing. */;
+ else if (cname)
{
dump_type (cname, flags);
pp_cxx_colon_colon (cxx_pp);
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 121950)
+++ cp/cp-tree.h (working copy)
@@ -3568,7 +3568,8 @@ enum overload_flags { NO_SPECIAL = 0, DT
template-declaration.
TFF_TEMPLATE_NAME: show only template-name.
TFF_EXPR_IN_PARENS: parenthesize expressions.
- TFF_NO_FUNCTION_ARGUMENTS: don't show function arguments. */
+ TFF_NO_FUNCTION_ARGUMENTS: don't show function arguments.
+ TFF_NO_OUTER_SCOPE: don't print the scope on the outermost declarator. */
#define TFF_PLAIN_IDENTIFIER (0)
#define TFF_SCOPE (1)
@@ -3582,6 +3583,7 @@ enum overload_flags { NO_SPECIAL = 0, DT
#define TFF_TEMPLATE_NAME (1 << 8)
#define TFF_EXPR_IN_PARENS (1 << 9)
#define TFF_NO_FUNCTION_ARGUMENTS (1 << 10)
+#define TFF_NO_OUTER_SCOPE (1 << 11)
/* Returns the TEMPLATE_DECL associated to a TEMPLATE_TEMPLATE_PARM
node. */
Index: cp/cp-lang.c
===================================================================
--- cp/cp-lang.c (revision 121950)
+++ cp/cp-lang.c (working copy)
@@ -36,6 +36,7 @@ Boston, MA 02110-1301, USA. */
enum c_language_kind c_language = clk_cxx;
static void cp_init_ts (void);
+static const char * cxx_dwarf_name (tree t, int verbosity);
/* Lang hooks common to C++ and ObjC++ are declared in cp/cp-objcp-common.h;
consequently, there should be very few hooks below. */
@@ -46,6 +47,8 @@ static void cp_init_ts (void);
#define LANG_HOOKS_INIT cxx_init
#undef LANG_HOOKS_DECL_PRINTABLE_NAME
#define LANG_HOOKS_DECL_PRINTABLE_NAME cxx_printable_name
+#undef LANG_HOOKS_DWARF_NAME
+#define LANG_HOOKS_DWARF_NAME cxx_dwarf_name
#undef LANG_HOOKS_FOLD_OBJ_TYPE_REF
#define LANG_HOOKS_FOLD_OBJ_TYPE_REF cp_fold_obj_type_ref
#undef LANG_HOOKS_INIT_TS
@@ -138,6 +141,17 @@ cp_init_ts (void)
}
+static const char *
+cxx_dwarf_name (tree t, int verbosity)
+{
+ gcc_assert (DECL_P (t));
+
+ if (verbosity >= 2)
+ return decl_as_string (t, TFF_DECL_SPECIFIERS | TFF_NO_OUTER_SCOPE);
+
+ return cxx_printable_name (t, verbosity);
+}
+
void
finish_file (void)
{
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 121950)
+++ cp/pt.c (working copy)
@@ -106,8 +106,6 @@ static void add_pending_template (tree);
static int push_tinst_level (tree);
static void pop_tinst_level (void);
static void reopen_tinst_level (tree);
-static tree classtype_mangled_name (tree);
-static char* mangle_class_name_for_template (const char *, tree, tree);
static tree tsubst_initializer_list (tree, tree);
static tree get_class_bindings (tree, tree, tree);
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
@@ -3349,14 +3347,7 @@ push_template_decl_real (tree decl, bool
info = tree_cons (tmpl, args, NULL_TREE);
if (DECL_IMPLICIT_TYPEDEF_P (decl))
- {
- SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
- if ((!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
- && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
- /* Don't change the name if we've already set it up. */
- && !IDENTIFIER_TEMPLATE (DECL_NAME (decl)))
- DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
- }
+ SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
else if (DECL_LANG_SPECIFIC (decl))
DECL_TEMPLATE_INFO (decl) = info;
@@ -4301,124 +4292,6 @@ comp_template_args (tree oldargs, tree n
return 1;
}
-/* Given class template name and parameter list, produce a user-friendly name
- for the instantiation. */
-
-static char *
-mangle_class_name_for_template (const char* name, tree parms, tree arglist)
-{
- static struct obstack scratch_obstack;
- static char *scratch_firstobj;
- int i, nparms;
-
- if (!scratch_firstobj)
- gcc_obstack_init (&scratch_obstack);
- else
- obstack_free (&scratch_obstack, scratch_firstobj);
- scratch_firstobj = (char *) obstack_alloc (&scratch_obstack, 1);
-
-#define ccat(C) obstack_1grow (&scratch_obstack, (C));
-#define cat(S) obstack_grow (&scratch_obstack, (S), strlen (S))
-
- cat (name);
- ccat ('<');
- nparms = TREE_VEC_LENGTH (parms);
- arglist = INNERMOST_TEMPLATE_ARGS (arglist);
- gcc_assert (nparms == TREE_VEC_LENGTH (arglist));
- for (i = 0; i < nparms; i++)
- {
- tree parm;
- tree arg;
-
- parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
- arg = TREE_VEC_ELT (arglist, i);
-
- if (parm == error_mark_node)
- continue;
-
- if (i)
- ccat (',');
-
- if (TREE_CODE (parm) == TYPE_DECL)
- {
- cat (type_as_string (arg, TFF_CHASE_TYPEDEF));
- continue;
- }
- else if (TREE_CODE (parm) == TEMPLATE_DECL)
- {
- if (TREE_CODE (arg) == TEMPLATE_DECL)
- {
- /* Already substituted with real template. Just output
- the template name here */
- tree context = DECL_CONTEXT (arg);
- if (context)
- {
- /* The template may be defined in a namespace, or
- may be a member template. */
- gcc_assert (TREE_CODE (context) == NAMESPACE_DECL
- || CLASS_TYPE_P (context));
- cat (decl_as_string (DECL_CONTEXT (arg),
- TFF_PLAIN_IDENTIFIER));
- cat ("::");
- }
- cat (IDENTIFIER_POINTER (DECL_NAME (arg)));
- }
- else
- /* Output the parameter declaration. */
- cat (type_as_string (arg, TFF_CHASE_TYPEDEF));
- continue;
- }
- else
- gcc_assert (TREE_CODE (parm) == PARM_DECL);
-
- /* No need to check arglist against parmlist here; we did that
- in coerce_template_parms, called from lookup_template_class. */
- cat (expr_as_string (arg, TFF_PLAIN_IDENTIFIER));
- }
- {
- char *bufp = obstack_next_free (&scratch_obstack);
- int offset = 0;
- while (bufp[offset - 1] == ' ')
- offset--;
- obstack_blank_fast (&scratch_obstack, offset);
-
- /* B<C<char> >, not B<C<char>> */
- if (bufp[offset - 1] == '>')
- ccat (' ');
- }
- ccat ('>');
- ccat ('\0');
- return (char *) obstack_base (&scratch_obstack);
-}
-
-static tree
-classtype_mangled_name (tree t)
-{
- if (CLASSTYPE_TEMPLATE_INFO (t)
- /* Specializations have already had their names set up in
- lookup_template_class. */
- && !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
- {
- tree tmpl = most_general_template (CLASSTYPE_TI_TEMPLATE (t));
-
- /* For non-primary templates, the template parameters are
- implicit from their surrounding context. */
- if (PRIMARY_TEMPLATE_P (tmpl))
- {
- tree name = DECL_NAME (tmpl);
- char *mangled_name = mangle_class_name_for_template
- (IDENTIFIER_POINTER (name),
- DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
- CLASSTYPE_TI_ARGS (t));
- tree id = get_identifier (mangled_name);
- IDENTIFIER_TEMPLATE (id) = name;
- return id;
- }
- }
-
- return TYPE_IDENTIFIER (t);
-}
-
static void
add_pending_template (tree d)
{
@@ -4965,10 +4838,6 @@ lookup_template_class (tree d1,
the instantiation and exit above. */
tsubst_enum (template_type, t, arglist);
- /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO
- is set up. */
- if (TREE_CODE (t) != ENUMERAL_TYPE)
- DECL_NAME (type_decl) = classtype_mangled_name (t);
if (is_partial_instantiation)
/* If the type makes use of template parameters, the
code that generates debugging information will crash. */