diff mbox

[C++] lang_decl selector & decomposition

Message ID 21a65173-8939-e6d8-0fa5-278d7a64ec3d@acm.org
State New
Headers show

Commit Message

Nathan Sidwell May 31, 2017, 4:54 p.m. UTC
This patch reworks how decl_decomposition is marked.  With the new 
lang_decl_decomp struct, the selector grew another used but -- which 
affected me on the modules branch.  however, we can use that use 
selector value in place of the decompostion_p bitfield.

This patch makes that change, but it also replaces the use of magic 
constants [0-4] with an enumeration.

Rather than have retrofit_lang_decl know about decomposition conversion, 
I broke out a fit_decomposition_lang_decl function for just that purpose.

The other change I made is breaking out new maybe_add_lang_decl_raw and 
maybe_add_lang_type_raw functions.  On the modules branch I need to 
recreate the lang_decl/lang_type nodes, but based on an untrustworth 
binary file.  So we don't want to assert if they're called incorrectly. 
I was going to leave that on the modules branch, until Jakub altered 
retrofit_lang_decl, and I had a more complicated merge.

Jakub, I discovered that fit_decomposition_lang_decl can get called 
repeatedly on the same var but with different base vars.  Is that expected?

nathan

Comments

Jakub Jelinek May 31, 2017, 5:05 p.m. UTC | #1
On Wed, May 31, 2017 at 12:54:24PM -0400, Nathan Sidwell wrote:
> This patch reworks how decl_decomposition is marked.  With the new
> lang_decl_decomp struct, the selector grew another used but -- which
> affected me on the modules branch.  however, we can use that use selector
> value in place of the decompostion_p bitfield.
> 
> This patch makes that change, but it also replaces the use of magic
> constants [0-4] with an enumeration.
> 
> Rather than have retrofit_lang_decl know about decomposition conversion, I
> broke out a fit_decomposition_lang_decl function for just that purpose.
> 
> The other change I made is breaking out new maybe_add_lang_decl_raw and
> maybe_add_lang_type_raw functions.  On the modules branch I need to recreate
> the lang_decl/lang_type nodes, but based on an untrustworth binary file.  So
> we don't want to assert if they're called incorrectly. I was going to leave
> that on the modules branch, until Jakub altered retrofit_lang_decl, and I
> had a more complicated merge.
> 
> Jakub, I discovered that fit_decomposition_lang_decl can get called
> repeatedly on the same var but with different base vars.  Is that expected?

That is weird, that sounds like a bug somewhere?  Which testcase is it on?

> 2017-05-31  Nathan Sidwell  <nathan@acm.org>
> 
> 	* cp-tree.h (lang_decl_slector): New enum.

selector?

	Jakub
Nathan Sidwell May 31, 2017, 5:16 p.m. UTC | #2
On 05/31/2017 01:05 PM, Jakub Jelinek wrote:

> That is weird, that sounds like a bug somewhere?  Which testcase is it on?

I think decomp25 & decomp7 & 8 (sorry, can't recall full name).
I discovered them because my first attempt had an assert that the 
incoming base was the same as the stored one, for the already-converted 
case.

It wasn't the case of turning a NULL into non-NULL.

nathan
Jakub Jelinek May 31, 2017, 5:18 p.m. UTC | #3
On Wed, May 31, 2017 at 01:16:36PM -0400, Nathan Sidwell wrote:
> On 05/31/2017 01:05 PM, Jakub Jelinek wrote:
> 
> > That is weird, that sounds like a bug somewhere?  Which testcase is it on?
> 
> I think decomp25 & decomp7 & 8 (sorry, can't recall full name).
> I discovered them because my first attempt had an assert that the incoming
> base was the same as the stored one, for the already-converted case.
> 
> It wasn't the case of turning a NULL into non-NULL.

Even that shouldn't happen.  NULL should be only for the base declaration,
i.e. the underlying artificial var, non-NULL should be set on the VAR_DECLs
for the user identifiers and should point to the underlying artificial var.

	Jakub
Jakub Jelinek June 5, 2017, 10:28 a.m. UTC | #4
On Wed, May 31, 2017 at 01:16:36PM -0400, Nathan Sidwell wrote:
> On 05/31/2017 01:05 PM, Jakub Jelinek wrote:
> 
> > That is weird, that sounds like a bug somewhere?  Which testcase is it on?
> 
> I think decomp25 & decomp7 & 8 (sorry, can't recall full name).
> I discovered them because my first attempt had an assert that the incoming
> base was the same as the stored one, for the already-converted case.

That doesn't look like a bug to me.
When instantiating structured binding inside of a template, the VAR_DECL is
created using copy_decl from the template VAR_DECL:
#0  0x00007ffff69a6521 in memcpy () from /lib64/libc.so.6
#1  0x00000000008ca690 in cxx_dup_lang_specific_decl (node=<var_decl 0x7fffefc23b40 d>) at ../../gcc/cp/lex.c:657
#2  0x00000000008ca6ee in copy_decl (decl=<var_decl 0x7fffefc01900 d>) at ../../gcc/cp/lex.c:675
#3  0x00000000009b174b in tsubst_decl (t=<var_decl 0x7fffefc01900 d>, args=<tree_vec 0x7fffefc2ef00>, complain=3) at ../../gcc/cp/pt.c:12860
#4  0x00000000009b3796 in tsubst (t=<var_decl 0x7fffefc01900 d>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>) at ../../gcc/cp/pt.c:13376
#5  0x00000000009bf6e8 in tsubst_decomp_names (decl=<var_decl 0x7fffefc23a20>, pattern_decl=<var_decl 0x7fffefc017e0>, 
    args=<tree_vec 0x7fffefc2ef00>, complain=3, in_decl=<template_decl 0x7fffefc1ad80 foo>, first=0x7fffffffd648, cnt=0x7fffffffd654)
    at ../../gcc/cp/pt.c:15719
#6  0x00000000009c0a5a in tsubst_expr (t=<decl_expr 0x7fffefc14ce0>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>, integral_constant_expression_p=false) at ../../gcc/cp/pt.c:15890
#7  0x00000000009bfc0d in tsubst_expr (t=<statement_list 0x7fffefc14c00>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>, integral_constant_expression_p=false) at ../../gcc/cp/pt.c:15771
#8  0x00000000009c1832 in tsubst_expr (t=<bind_expr 0x7fffefabea80>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>, integral_constant_expression_p=false) at ../../gcc/cp/pt.c:15998
#9  0x00000000009e2d6d in instantiate_decl (d=<function_decl 0x7fffefc1c900 foo>, defer_ok=false, expl_inst_class_mem_p=false)
    at ../../gcc/cp/pt.c:22965
and then finalized later:
#0  fit_decomposition_lang_decl (t=<var_decl 0x7fffefc23b40 d>, base=<var_decl 0x7fffefc23a20>) at ../../gcc/cp/lex.c:588
#1  0x000000000084a584 in cp_finish_decomp (decl=<var_decl 0x7fffefc23a20>, first=<var_decl 0x7fffefc23b40 d>, count=2)
    at ../../gcc/cp/decl.c:7387
#2  0x00000000009c0a9b in tsubst_expr (t=<decl_expr 0x7fffefc14ce0>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>, integral_constant_expression_p=false) at ../../gcc/cp/pt.c:15894
#3  0x00000000009bfc0d in tsubst_expr (t=<statement_list 0x7fffefc14c00>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>, integral_constant_expression_p=false) at ../../gcc/cp/pt.c:15771
#4  0x00000000009c1832 in tsubst_expr (t=<bind_expr 0x7fffefabea80>, args=<tree_vec 0x7fffefc2ef00>, complain=3, 
    in_decl=<template_decl 0x7fffefc1ad80 foo>, integral_constant_expression_p=false) at ../../gcc/cp/pt.c:15998
#5  0x00000000009e2d6d in instantiate_decl (d=<function_decl 0x7fffefc1c900 foo>, defer_ok=false, expl_inst_class_mem_p=false)
    at ../../gcc/cp/pt.c:22965

So unless cxx_dup_lang_specific_decl or copy_decl or tsubst_decl
clears the DECL_DECOMP_BASE for the short time before cp_finish_decomp
is called, DECL_DECOMP_BASE will be "wrong" for a short time, but it
shouldn't matter, nothing should be querying it in between.  Setting
it to NULL wouldn't be correct either anyway.

	Jakub
Nathan Sidwell June 5, 2017, 11:22 a.m. UTC | #5
On 06/05/2017 06:28 AM, Jakub Jelinek wrote:

> So unless cxx_dup_lang_specific_decl or copy_decl or tsubst_decl
> clears the DECL_DECOMP_BASE for the short time before cp_finish_decomp
> is called, DECL_DECOMP_BASE will be "wrong" for a short time, but it
> shouldn't matter, nothing should be querying it in between.  Setting
> it to NULL wouldn't be correct either anyway.

Ok, thanks for checking.  That also explains why we can meet VAR_DECLs 
that already have a decomp_lang_decl extension.

nathan
diff mbox

Patch

2017-05-31  Nathan Sidwell  <nathan@acm.org>

	* cp-tree.h (lang_decl_slector): New enum.
	(lang_decl_base): Make selector an enum.  Drop decomposition_p
	field.
	(lang_decl): Use enum for discrimination.
	(LANG_DECL_FN_CHECK, LANG_DECL_NS_CHECK, LANG_DECL_PARM_CHECK,
	LANG_DECL_DEOMP_CHECK): Use enum.
	(DECL_DECOMPOSITION_P): Use selector value.
	(SET_DECL_DECOMPOSITION_P): Delete.
	(retrofit_lang_decl): Lose SEL parm.
	(fit_decomposition_lang_decl): Declare.
	* decl.c (cp_finish_decomp, grokdeclarator): Use
	fit_decomposition_lang_decl.
	* lex.c (maybe_add_lang_decl_raw): New. Broken out of
	retrofit_lang_decl.
	(set_decl_linkage): New.  Broken out of retrofit_lang_decl.  Use enum.
	(fit_decomposition_lang_decl): Likewise.
	(retrofit_lang_decl): Use worker functions.
	(cxx_dup_lang_specific_decl): Use selector enum.
	(maybe_add_lang_type_raw): New.  Broken out of ...
	(cxx_make_type_name): ... here.  Call it.

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 248745)
+++ cp/cp-tree.h	(working copy)
@@ -2423,13 +2423,25 @@  struct GTY(()) lang_type {
 #define NAMESPACE_LEVEL(NODE) \
   (LANG_DECL_NS_CHECK (NODE)->level)
 
+/* Discriminator values for lang_decl.  */
+
+enum lang_decl_selector
+{
+  lds_min,
+  lds_fn,
+  lds_ns,
+  lds_parm,
+  lds_decomp
+};
+
 /* Flags shared by all forms of DECL_LANG_SPECIFIC.
 
    Some of the flags live here only to make lang_decl_min/fn smaller.  Do
    not make this struct larger than 32 bits; instead, make sel smaller.  */
o 
 struct GTY(()) lang_decl_base {
-  unsigned selector : 16;   /* Larger than necessary for faster access.  */
+  /* Larger than necessary for faster access.  */
+  ENUM_BITFIELD(lang_decl_selector) selector : 16;
   ENUM_BITFIELD(languages) language : 1;
   unsigned use_template : 2;
   unsigned not_really_extern : 1;	   /* var or fn */
@@ -2444,8 +2456,7 @@  struct GTY(()) lang_decl_base {
   unsigned u2sel : 1;
   unsigned concept_p : 1;                  /* applies to vars and functions */
   unsigned var_declared_inline_p : 1;	   /* var */
-  unsigned decomposition_p : 1;		   /* var */
-  /* 1 spare bit */
+  /* 2 spare bits */
 };
 
 /* True for DECL codes which have template info and access.  */
@@ -2577,12 +2588,13 @@  struct GTY(()) lang_decl_decomp {
 
 struct GTY(()) lang_decl {
   union GTY((desc ("%h.base.selector"))) lang_decl_u {
+     /* Nothing of only the base type exists.  */
     struct lang_decl_base GTY ((default)) base;
-    struct lang_decl_min GTY((tag ("0"))) min;
-    struct lang_decl_fn GTY ((tag ("1"))) fn;
-    struct lang_decl_ns GTY((tag ("2"))) ns;
-    struct lang_decl_parm GTY((tag ("3"))) parm;
-    struct lang_decl_decomp GTY((tag ("4"))) decomp;
+    struct lang_decl_min GTY((tag ("lds_min"))) min;
+    struct lang_decl_fn GTY ((tag ("lds_fn"))) fn;
+    struct lang_decl_ns GTY((tag ("lds_ns"))) ns;
+    struct lang_decl_parm GTY((tag ("lds_parm"))) parm;
+    struct lang_decl_decomp GTY((tag ("lds_decomp"))) decomp;
   } u;
 };
 
@@ -2603,26 +2615,29 @@  struct GTY(()) lang_decl {
    lang_decl_fn, look down through a TEMPLATE_DECL into its result.  */
 #define LANG_DECL_FN_CHECK(NODE) __extension__				\
 ({ struct lang_decl *lt = DECL_LANG_SPECIFIC (STRIP_TEMPLATE (NODE));	\
-   if (!DECL_DECLARES_FUNCTION_P (NODE) || lt->u.base.selector != 1)	\
+   if (!DECL_DECLARES_FUNCTION_P (NODE)					\
+       || lt->u.base.selector != lds_fn)				\
      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);		\
    &lt->u.fn; })
 
 #define LANG_DECL_NS_CHECK(NODE) __extension__				\
 ({ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);			\
-   if (TREE_CODE (NODE) != NAMESPACE_DECL || lt->u.base.selector != 2)	\
+   if (TREE_CODE (NODE) != NAMESPACE_DECL				\
+       || lt->u.base.selector != lds_ns)				\
      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);		\
    &lt->u.ns; })
 
 #define LANG_DECL_PARM_CHECK(NODE) __extension__		\
 ({ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);		\
-  if (TREE_CODE (NODE) != PARM_DECL)				\
+  if (TREE_CODE (NODE) != PARM_DECL				\
+      || lt->u.base.selector != lds_parm)			\
     lang_check_failed (__FILE__, __LINE__, __FUNCTION__);	\
   &lt->u.parm; })
 
 #define LANG_DECL_DECOMP_CHECK(NODE) __extension__		\
 ({ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);		\
   if (!VAR_P (NODE)						\
-      || lt->u.base.selector != 4)				\
+      || lt->u.base.selector != lds_decomp)			\
     lang_check_failed (__FILE__, __LINE__, __FUNCTION__);	\
   &lt->u.decomp; })
 
@@ -3893,11 +3908,8 @@  more_aggr_init_expr_args_p (const aggr_i
    declaration or one of VAR_DECLs for the user identifiers in it.  */
 #define DECL_DECOMPOSITION_P(NODE) \
   (VAR_P (NODE) && DECL_LANG_SPECIFIC (NODE)			\
-   ? DECL_LANG_SPECIFIC (NODE)->u.base.decomposition_p		\
+   ? DECL_LANG_SPECIFIC (NODE)->u.base.selector == lds_decomp		\
    : false)
-#define SET_DECL_DECOMPOSITION_P(NODE) \
-  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.decomposition_p \
-   = true)
 
 /* The underlying artificial VAR_DECL for structured binding.  */
 #define DECL_DECOMP_BASE(NODE) \
@@ -6338,7 +6350,8 @@  extern tree unqualified_name_lookup_erro
 extern tree unqualified_fn_lookup_error		(cp_expr);
 extern tree build_lang_decl			(enum tree_code, tree, tree);
 extern tree build_lang_decl_loc			(location_t, enum tree_code, tree, tree);
-extern void retrofit_lang_decl			(tree, int = 0);
+extern void retrofit_lang_decl			(tree);
+extern void fit_decomposition_lang_decl		(tree, tree);
 extern tree copy_decl				(tree CXX_MEM_STAT_INFO);
 extern tree copy_type				(tree CXX_MEM_STAT_INFO);
 extern tree cxx_make_type			(enum tree_code);
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 248745)
+++ cp/decl.c	(working copy)
@@ -7372,11 +7372,7 @@  cp_finish_decomp (tree decl, tree first,
 	      DECL_HAS_VALUE_EXPR_P (first) = 1;
 	    }
 	  if (processing_template_decl)
-	    {
-	      retrofit_lang_decl (first, 4);
-	      SET_DECL_DECOMPOSITION_P (first);
-	      DECL_DECOMP_BASE (first) = decl;
-	    }
+	    fit_decomposition_lang_decl (first, decl);
 	  first = DECL_CHAIN (first);
 	}
       return;
@@ -7388,9 +7384,7 @@  cp_finish_decomp (tree decl, tree first,
   for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
     {
       v[count - i - 1] = d;
-      retrofit_lang_decl (d, 4);
-      SET_DECL_DECOMPOSITION_P (d);
-      DECL_DECOMP_BASE (d) = decl;
+      fit_decomposition_lang_decl (d, decl);
     }
 
   tree type = TREE_TYPE (decl);
@@ -12314,10 +12308,8 @@  grokdeclarator (const cp_declarator *dec
 	  {
 	    gcc_assert (declarator && declarator->kind == cdk_decomp);
 	    DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
-	    retrofit_lang_decl (decl, 4);
 	    DECL_ARTIFICIAL (decl) = 1;
-	    SET_DECL_DECOMPOSITION_P (decl);
-	    DECL_DECOMP_BASE (decl) = NULL_TREE;
+	    fit_decomposition_lang_decl (decl, NULL_TREE);
 	  }
       }
 
Index: cp/lex.c
===================================================================
--- cp/lex.c	(revision 248745)
+++ cp/lex.c	(working copy)
@@ -525,53 +525,52 @@  build_lang_decl_loc (location_t loc, enu
   return t;
 }
 
-/* Add DECL_LANG_SPECIFIC info to T.  Called from build_lang_decl
-   and pushdecl (for functions generated by the back end).  */
+/* Maybe add a raw lang_decl to T, a decl.  Return true if it needed
+   one.  */
 
-void
-retrofit_lang_decl (tree t, int sel)
+static bool
+maybe_add_lang_decl_raw (tree t, bool decomp_p)
 {
-  struct lang_decl *ld;
   size_t size;
-  size_t oldsize = 0;
-
-  if (DECL_LANG_SPECIFIC (t))
-    {
-      if (sel)
-	{
-	  if (DECL_LANG_SPECIFIC (t)->u.base.selector == sel)
-	    return;
-	  gcc_assert (DECL_LANG_SPECIFIC (t)->u.base.selector == 0);
-	  oldsize = sizeof (struct lang_decl_min);
-	}
-      else
-	return;
-    }
+  lang_decl_selector sel;
 
-  if (sel == 4)
-    size = sizeof (struct lang_decl_decomp);
+  if (decomp_p)
+    sel = lds_decomp, size = sizeof (struct lang_decl_decomp);
   else if (TREE_CODE (t) == FUNCTION_DECL)
-    sel = 1, size = sizeof (struct lang_decl_fn);
+    sel = lds_fn, size = sizeof (struct lang_decl_fn);
   else if (TREE_CODE (t) == NAMESPACE_DECL)
-    sel = 2, size = sizeof (struct lang_decl_ns);
+    sel = lds_ns, size = sizeof (struct lang_decl_ns);
   else if (TREE_CODE (t) == PARM_DECL)
-    sel = 3, size = sizeof (struct lang_decl_parm);
+    sel = lds_parm, size = sizeof (struct lang_decl_parm);
   else if (LANG_DECL_HAS_MIN (t))
-    sel = 0, size = sizeof (struct lang_decl_min);
+    sel = lds_min, size = sizeof (struct lang_decl_min);
   else
-    gcc_unreachable ();
+    return false;
 
-  ld = (struct lang_decl *) ggc_internal_cleared_alloc (size);
-  if (oldsize)
-    memcpy (ld, DECL_LANG_SPECIFIC (t), oldsize);
+  struct lang_decl *ld
+    = (struct lang_decl *) ggc_internal_cleared_alloc (size);
 
   ld->u.base.selector = sel;
   DECL_LANG_SPECIFIC (t) = ld;
 
-  if (sel == 2)
+  if (sel == lds_ns)
     /* Who'd create a namespace, only to put nothing in it?  */
     ld->u.ns.bindings = hash_map<lang_identifier *, tree>::create_ggc (499);
 
+  if (GATHER_STATISTICS)
+    {
+      tree_node_counts[(int)lang_decl] += 1;
+      tree_node_sizes[(int)lang_decl] += size;
+    }
+  return true;
+}
+
+/* T has just had a decl_lang_specific added.  Initialize its
+   linkage.  */
+
+static void
+set_decl_linkage (tree t)
+{
   if (current_lang_name == lang_name_cplusplus
       || decl_linkage (t) == lk_none)
     SET_DECL_LANGUAGE (t, lang_cplusplus);
@@ -579,37 +578,79 @@  retrofit_lang_decl (tree t, int sel)
     SET_DECL_LANGUAGE (t, lang_c);
   else
     gcc_unreachable ();
+}
 
-  if (GATHER_STATISTICS)
+/* T is a VAR_DECL node that needs to be a decomposition of BASE.  */
+
+void
+fit_decomposition_lang_decl (tree t, tree base)
+{
+  if (struct lang_decl *orig_ld = DECL_LANG_SPECIFIC (t))
     {
-      tree_node_counts[(int)lang_decl] += 1;
-      tree_node_sizes[(int)lang_decl] += size;
+      if (orig_ld->u.base.selector == lds_min)
+	{
+	  maybe_add_lang_decl_raw (t, true);
+	  memcpy (DECL_LANG_SPECIFIC (t), orig_ld,
+		  sizeof (struct lang_decl_min));
+	  /* Reset selector, which will have been bashed by the
+	     memcpy.  */
+	  DECL_LANG_SPECIFIC (t)->u.base.selector = lds_decomp;
+	}
+      else
+	gcc_checking_assert (orig_ld->u.base.selector == lds_decomp);
     }
+  else
+    {
+      maybe_add_lang_decl_raw (t, true);
+      set_decl_linkage (t);
+    }
+
+  DECL_DECOMP_BASE (t) = base;
+}
+
+/* Add DECL_LANG_SPECIFIC info to T, if it needs one.  Generally
+   every C++ decl needs one, but C builtins etc do not.   */
+
+void
+retrofit_lang_decl (tree t)
+{
+  if (DECL_LANG_SPECIFIC (t))
+    return;
+
+  if (maybe_add_lang_decl_raw (t, false))
+    set_decl_linkage (t);
 }
 
 void
 cxx_dup_lang_specific_decl (tree node)
 {
   int size;
-  struct lang_decl *ld;
 
   if (! DECL_LANG_SPECIFIC (node))
     return;
 
-  if (TREE_CODE (node) == FUNCTION_DECL)
-    size = sizeof (struct lang_decl_fn);
-  else if (TREE_CODE (node) == NAMESPACE_DECL)
-    size = sizeof (struct lang_decl_ns);
-  else if (TREE_CODE (node) == PARM_DECL)
-    size = sizeof (struct lang_decl_parm);
-  else if (DECL_DECOMPOSITION_P (node))
-    size = sizeof (struct lang_decl_decomp);
-  else if (LANG_DECL_HAS_MIN (node))
-    size = sizeof (struct lang_decl_min);
-  else
-    gcc_unreachable ();
+  switch (DECL_LANG_SPECIFIC (node)->u.base.selector)
+    {
+    case lds_min:
+      size = sizeof (struct lang_decl_min);
+      break;
+    case lds_fn:
+      size = sizeof (struct lang_decl_fn);
+      break;
+    case lds_ns:
+      size = sizeof (struct lang_decl_ns);
+      break;
+    case lds_parm:
+      size = sizeof (struct lang_decl_parm);
+      break;
+    case lds_decomp:
+      size = sizeof (struct lang_decl_decomp);
+      break;
+    default:
+      gcc_unreachable ();
+    }
 
-  ld = (struct lang_decl *) ggc_internal_alloc (size);
+  struct lang_decl *ld = (struct lang_decl *) ggc_internal_alloc (size);
   memcpy (ld, DECL_LANG_SPECIFIC (node), size);
   DECL_LANG_SPECIFIC (node) = ld;
 
@@ -670,18 +711,18 @@  copy_type (tree type MEM_STAT_DECL)
   return copy;
 }
 
-tree
-cxx_make_type (enum tree_code code)
-{
-  tree t = make_node (code);
+/* Add a raw lang_type to T, a type, should it need one.  */
 
-  /* Create lang_type structure.  */
-  if (RECORD_OR_UNION_CODE_P (code)
-      || code == BOUND_TEMPLATE_TEMPLATE_PARM)
+static bool
+maybe_add_lang_type_raw (tree t)
+{
+  bool add = (RECORD_OR_UNION_CODE_P (TREE_CODE (t))
+	      || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM);
+  if (add)
     {
       struct lang_type *pi
-          = (struct lang_type *) ggc_internal_cleared_alloc
-	  (sizeof (struct lang_type));
+	= (struct lang_type *) ggc_internal_cleared_alloc
+	(sizeof (struct lang_type));
 
       TYPE_LANG_SPECIFIC (t) = pi;
       pi->u.c.h.is_lang_type_class = 1;
@@ -692,6 +733,15 @@  cxx_make_type (enum tree_code code)
 	  tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
 	}
     }
+  return add;
+}
+
+tree
+cxx_make_type (enum tree_code code)
+{
+  tree t = make_node (code);
+
+  maybe_add_lang_type_raw (t);
 
   /* Set up some flags that give proper default behavior.  */
   if (RECORD_OR_UNION_CODE_P (code))