]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Move pass free_lang_data to its own file.
authorMartin Sebor <msebor@redhat.com>
Thu, 29 Apr 2021 01:01:40 +0000 (19:01 -0600)
committerMartin Sebor <msebor@redhat.com>
Thu, 29 Apr 2021 01:05:41 +0000 (19:05 -0600)
gcc/ChangeLog:
* Makefile.in (OBJS): Add ipa-free-lang-data.o.
* ipa-free-lang-data.cc: New file.
* tree.c: Move pass free_lang_data to file above.
 (build_array_type_1): Declare extern.
* tree.h (build_array_type_1): Declare.

gcc/Makefile.in
gcc/ipa-free-lang-data.cc [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 8a5fb3fd99c1ab850631d2ccb9f3466170b81b40..81c0d608b736463fd9c82d54aa7a2c37e272c004 100644 (file)
@@ -1446,6 +1446,7 @@ OBJS = \
        ipa-split.o \
        ipa-inline.o \
        ipa-comdats.o \
+       ipa-free-lang-data.o \
        ipa-visibility.o \
        ipa-inline-analysis.o \
        ipa-inline-transform.o \
diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc
new file mode 100644 (file)
index 0000000..0f2d43b
--- /dev/null
@@ -0,0 +1,1188 @@
+/* Pass to free or clear language-specific data structures from
+   the IL before they reach the middle end.
+
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file contains the low level primitives for operating on tree nodes,
+   including allocation, list operations, interning of identifiers,
+   construction of data type nodes and statement nodes,
+   and construction of type conversion nodes.  It also contains
+   tables index by tree code that describe how to take apart
+   nodes of that code.
+
+   It is intended to be language-independent but can occasionally
+   calls language-dependent routines.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "alias.h"
+#include "attribs.h"
+#include "langhooks.h"
+#include "gimple-iterator.h"
+#include "langhooks-def.h"
+#include "tree-diagnostic.h"
+#include "except.h"
+#include "ipa-utils.h"
+
+namespace {
+
+/* Data used when collecting DECLs and TYPEs for language data removal.  */
+
+class free_lang_data_d
+{
+public:
+  free_lang_data_d () : decls (100), types (100) {}
+
+  /* Worklist to avoid excessive recursion.  */
+  auto_vec<tree> worklist;
+
+  /* Set of traversed objects.  Used to avoid duplicate visits.  */
+  hash_set<tree> pset;
+
+  /* Array of symbols to process with free_lang_data_in_decl.  */
+  auto_vec<tree> decls;
+
+  /* Array of types to process with free_lang_data_in_type.  */
+  auto_vec<tree> types;
+};
+
+
+/* Add type or decl T to one of the list of tree nodes that need their
+   language data removed.  The lists are held inside FLD.  */
+
+static void
+add_tree_to_fld_list (tree t, class free_lang_data_d *fld)
+{
+  if (DECL_P (t))
+    fld->decls.safe_push (t);
+  else if (TYPE_P (t))
+    fld->types.safe_push (t);
+  else
+    gcc_unreachable ();
+}
+
+/* Push tree node T into FLD->WORKLIST.  */
+
+static inline void
+fld_worklist_push (tree t, class free_lang_data_d *fld)
+{
+  if (t && !is_lang_specific (t) && !fld->pset.contains (t))
+    fld->worklist.safe_push ((t));
+}
+
+
+\f
+/* Return simplified TYPE_NAME of TYPE.  */
+
+static tree
+fld_simplified_type_name (tree type)
+{
+  if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL)
+    return TYPE_NAME (type);
+  /* Drop TYPE_DECLs in TYPE_NAME in favor of the identifier in the
+     TYPE_DECL if the type doesn't have linkage.
+     this must match fld_  */
+  if (type != TYPE_MAIN_VARIANT (type)
+      || (!DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (type))
+         && (TREE_CODE (type) != RECORD_TYPE
+             || !TYPE_BINFO (type)
+             || !BINFO_VTABLE (TYPE_BINFO (type)))))
+    return DECL_NAME (TYPE_NAME (type));
+  return TYPE_NAME (type);
+}
+
+/* Do same comparsion as check_qualified_type skipping lang part of type
+   and be more permissive about type names: we only care that names are
+   same (for diagnostics) and that ODR names are the same.
+   If INNER_TYPE is non-NULL, be sure that TREE_TYPE match it.  */
+
+static bool
+fld_type_variant_equal_p (tree t, tree v, tree inner_type)
+{
+  if (TYPE_QUALS (t) != TYPE_QUALS (v)
+      /* We want to match incomplete variants with complete types.
+        In this case we need to ignore alignment.   */
+      || ((!RECORD_OR_UNION_TYPE_P (t) || COMPLETE_TYPE_P (v))
+         && (TYPE_ALIGN (t) != TYPE_ALIGN (v)
+             || TYPE_USER_ALIGN (t) != TYPE_USER_ALIGN (v)))
+      || fld_simplified_type_name (t) != fld_simplified_type_name (v)
+      || !attribute_list_equal (TYPE_ATTRIBUTES (t),
+                               TYPE_ATTRIBUTES (v))
+      || (inner_type && TREE_TYPE (v) != inner_type))
+    return false;
+
+  return true;
+}
+
+/* Find variant of FIRST that match T and create new one if necessary.
+   Set TREE_TYPE to INNER_TYPE if non-NULL.  */
+
+static tree
+fld_type_variant (tree first, tree t, class free_lang_data_d *fld,
+                 tree inner_type = NULL)
+{
+  if (first == TYPE_MAIN_VARIANT (t))
+    return t;
+  for (tree v = first; v; v = TYPE_NEXT_VARIANT (v))
+    if (fld_type_variant_equal_p (t, v, inner_type))
+      return v;
+  tree v = build_variant_type_copy (first);
+  TYPE_READONLY (v) = TYPE_READONLY (t);
+  TYPE_VOLATILE (v) = TYPE_VOLATILE (t);
+  TYPE_ATOMIC (v) = TYPE_ATOMIC (t);
+  TYPE_RESTRICT (v) = TYPE_RESTRICT (t);
+  TYPE_ADDR_SPACE (v) = TYPE_ADDR_SPACE (t);
+  TYPE_NAME (v) = TYPE_NAME (t);
+  TYPE_ATTRIBUTES (v) = TYPE_ATTRIBUTES (t);
+  TYPE_CANONICAL (v) = TYPE_CANONICAL (t);
+  /* Variants of incomplete types should have alignment
+     set to BITS_PER_UNIT.  Do not copy the actual alignment.  */
+  if (!RECORD_OR_UNION_TYPE_P (v) || COMPLETE_TYPE_P (v))
+    {
+      SET_TYPE_ALIGN (v, TYPE_ALIGN (t));
+      TYPE_USER_ALIGN (v) = TYPE_USER_ALIGN (t);
+    }
+  if (inner_type)
+    TREE_TYPE (v) = inner_type;
+  gcc_checking_assert (fld_type_variant_equal_p (t,v, inner_type));
+  if (!fld->pset.add (v))
+    add_tree_to_fld_list (v, fld);
+  return v;
+}
+
+/* Map complete types to incomplete types.  */
+
+static hash_map<tree, tree> *fld_incomplete_types;
+
+/* Map types to simplified types.  */
+
+static hash_map<tree, tree> *fld_simplified_types;
+
+/* Produce variant of T whose TREE_TYPE is T2. If it is main variant,
+   use MAP to prevent duplicates.  */
+
+static tree
+fld_process_array_type (tree t, tree t2, hash_map<tree, tree> *map,
+                       class free_lang_data_d *fld)
+{
+  if (TREE_TYPE (t) == t2)
+    return t;
+
+  if (TYPE_MAIN_VARIANT (t) != t)
+    {
+      return fld_type_variant
+       (fld_process_array_type (TYPE_MAIN_VARIANT (t),
+                                TYPE_MAIN_VARIANT (t2), map, fld),
+        t, fld, t2);
+    }
+
+  bool existed;
+  tree &array
+    = map->get_or_insert (t, &existed);
+  if (!existed)
+    {
+      array
+       = build_array_type_1 (t2, TYPE_DOMAIN (t), TYPE_TYPELESS_STORAGE (t),
+                             false, false);
+      TYPE_CANONICAL (array) = TYPE_CANONICAL (t);
+      if (!fld->pset.add (array))
+       add_tree_to_fld_list (array, fld);
+    }
+  return array;
+}
+
+/* Return CTX after removal of contexts that are not relevant  */
+
+static tree
+fld_decl_context (tree ctx)
+{
+  /* Variably modified types are needed for tree_is_indexable to decide
+     whether the type needs to go to local or global section.
+     This code is semi-broken but for now it is easiest to keep contexts
+     as expected.  */
+  if (ctx && TYPE_P (ctx)
+      && !variably_modified_type_p (ctx, NULL_TREE))
+    {
+      while (ctx && TYPE_P (ctx))
+       ctx = TYPE_CONTEXT (ctx);
+    }
+  return ctx;
+}
+
+/* For T being aggregate type try to turn it into a incomplete variant.
+   Return T if no simplification is possible.  */
+
+static tree
+fld_incomplete_type_of (tree t, class free_lang_data_d *fld)
+{
+  if (!t)
+    return NULL;
+  if (POINTER_TYPE_P (t))
+    {
+      tree t2 = fld_incomplete_type_of (TREE_TYPE (t), fld);
+      if (t2 != TREE_TYPE (t))
+       {
+         tree first;
+         if (TREE_CODE (t) == POINTER_TYPE)
+           first = build_pointer_type_for_mode (t2, TYPE_MODE (t),
+                                                TYPE_REF_CAN_ALIAS_ALL (t));
+         else
+           first = build_reference_type_for_mode (t2, TYPE_MODE (t),
+                                                  TYPE_REF_CAN_ALIAS_ALL (t));
+         gcc_assert (TYPE_CANONICAL (t2) != t2
+                     && TYPE_CANONICAL (t2) == TYPE_CANONICAL (TREE_TYPE (t)));
+         if (!fld->pset.add (first))
+           add_tree_to_fld_list (first, fld);
+         return fld_type_variant (first, t, fld);
+       }
+      return t;
+    }
+  if (TREE_CODE (t) == ARRAY_TYPE)
+    return fld_process_array_type (t,
+                                  fld_incomplete_type_of (TREE_TYPE (t), fld),
+                                  fld_incomplete_types, fld);
+  if ((!RECORD_OR_UNION_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
+      || !COMPLETE_TYPE_P (t))
+    return t;
+  if (TYPE_MAIN_VARIANT (t) == t)
+    {
+      bool existed;
+      tree &copy
+       = fld_incomplete_types->get_or_insert (t, &existed);
+
+      if (!existed)
+       {
+         copy = build_distinct_type_copy (t);
+
+         /* It is possible that type was not seen by free_lang_data yet.  */
+         if (!fld->pset.add (copy))
+           add_tree_to_fld_list (copy, fld);
+         TYPE_SIZE (copy) = NULL;
+         TYPE_USER_ALIGN (copy) = 0;
+         TYPE_SIZE_UNIT (copy) = NULL;
+         TYPE_CANONICAL (copy) = TYPE_CANONICAL (t);
+         TREE_ADDRESSABLE (copy) = 0;
+         if (AGGREGATE_TYPE_P (t))
+           {
+             SET_TYPE_MODE (copy, VOIDmode);
+             SET_TYPE_ALIGN (copy, BITS_PER_UNIT);
+             TYPE_TYPELESS_STORAGE (copy) = 0;
+             TYPE_FIELDS (copy) = NULL;
+             TYPE_BINFO (copy) = NULL;
+             TYPE_FINAL_P (copy) = 0;
+             TYPE_EMPTY_P (copy) = 0;
+           }
+         else
+           {
+             TYPE_VALUES (copy) = NULL;
+             ENUM_IS_OPAQUE (copy) = 0;
+             ENUM_IS_SCOPED (copy) = 0;
+           }
+
+         /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
+            This is needed for ODR violation warnings to come out right (we
+            want duplicate TYPE_DECLs whenever the type is duplicated because
+            of ODR violation.  Because lang data in the TYPE_DECL may not
+            have been freed yet, rebuild it from scratch and copy relevant
+            fields.  */
+         TYPE_NAME (copy) = fld_simplified_type_name (copy);
+         tree name = TYPE_NAME (copy);
+
+         if (name && TREE_CODE (name) == TYPE_DECL)
+           {
+             gcc_checking_assert (TREE_TYPE (name) == t);
+             tree name2 = build_decl (DECL_SOURCE_LOCATION (name), TYPE_DECL,
+                                      DECL_NAME (name), copy);
+             if (DECL_ASSEMBLER_NAME_SET_P (name))
+               SET_DECL_ASSEMBLER_NAME (name2, DECL_ASSEMBLER_NAME (name));
+             SET_DECL_ALIGN (name2, 0);
+             DECL_CONTEXT (name2) = fld_decl_context
+               (DECL_CONTEXT (name));
+             TYPE_NAME (copy) = name2;
+           }
+       }
+      return copy;
+    }
+  return (fld_type_variant
+         (fld_incomplete_type_of (TYPE_MAIN_VARIANT (t), fld), t, fld));
+}
+
+/* Simplify type T for scenarios where we do not need complete pointer
+   types.  */
+
+static tree
+fld_simplified_type (tree t, class free_lang_data_d *fld)
+{
+  if (!t)
+    return t;
+  if (POINTER_TYPE_P (t))
+    return fld_incomplete_type_of (t, fld);
+  /* FIXME: This triggers verification error, see PR88140.  */
+#if 0
+  if (TREE_CODE (t) == ARRAY_TYPE)
+    return fld_process_array_type (t, fld_simplified_type (TREE_TYPE (t), fld),
+                                  fld_simplified_types, fld);
+#endif
+  return t;
+}
+
+/* Reset the expression *EXPR_P, a size or position.
+
+   ??? We could reset all non-constant sizes or positions.  But it's cheap
+   enough to not do so and refrain from adding workarounds to dwarf2out.c.
+
+   We need to reset self-referential sizes or positions because they cannot
+   be gimplified and thus can contain a CALL_EXPR after the gimplification
+   is finished, which will run afoul of LTO streaming.  And they need to be
+   reset to something essentially dummy but not constant, so as to preserve
+   the properties of the object they are attached to.  */
+
+static inline void
+free_lang_data_in_one_sizepos (tree *expr_p)
+{
+  tree expr = *expr_p;
+  if (CONTAINS_PLACEHOLDER_P (expr))
+    *expr_p = build0 (PLACEHOLDER_EXPR, TREE_TYPE (expr));
+}
+
+
+/* Reset all the fields in a binfo node BINFO.  We only keep
+   BINFO_VTABLE, which is used by gimple_fold_obj_type_ref.  */
+
+static void
+free_lang_data_in_binfo (tree binfo)
+{
+  unsigned i;
+  tree t;
+
+  gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
+
+  BINFO_VIRTUALS (binfo) = NULL_TREE;
+  BINFO_BASE_ACCESSES (binfo) = NULL;
+  BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
+  BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
+  BINFO_VPTR_FIELD (binfo) = NULL_TREE;
+  TREE_PUBLIC (binfo) = 0;
+
+  FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (binfo), i, t)
+    free_lang_data_in_binfo (t);
+}
+
+
+/* Reset all language specific information still present in TYPE.  */
+
+static void
+free_lang_data_in_type (tree type, class free_lang_data_d *fld)
+{
+  gcc_assert (TYPE_P (type));
+
+  /* Give the FE a chance to remove its own data first.  */
+  lang_hooks.free_lang_data (type);
+
+  TREE_LANG_FLAG_0 (type) = 0;
+  TREE_LANG_FLAG_1 (type) = 0;
+  TREE_LANG_FLAG_2 (type) = 0;
+  TREE_LANG_FLAG_3 (type) = 0;
+  TREE_LANG_FLAG_4 (type) = 0;
+  TREE_LANG_FLAG_5 (type) = 0;
+  TREE_LANG_FLAG_6 (type) = 0;
+
+  TYPE_NEEDS_CONSTRUCTING (type) = 0;
+
+  /* Purge non-marked variants from the variants chain, so that they
+     don't reappear in the IL after free_lang_data.  */
+  while (TYPE_NEXT_VARIANT (type)
+        && !fld->pset.contains (TYPE_NEXT_VARIANT (type)))
+    {
+      tree t = TYPE_NEXT_VARIANT (type);
+      TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
+      /* Turn the removed types into distinct types.  */
+      TYPE_MAIN_VARIANT (t) = t;
+      TYPE_NEXT_VARIANT (t) = NULL_TREE;
+    }
+
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    {
+      TREE_TYPE (type) = fld_simplified_type (TREE_TYPE (type), fld);
+      /* Remove the const and volatile qualifiers from arguments.  The
+        C++ front end removes them, but the C front end does not,
+        leading to false ODR violation errors when merging two
+        instances of the same function signature compiled by
+        different front ends.  */
+      for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
+       {
+         TREE_VALUE (p) = fld_simplified_type (TREE_VALUE (p), fld);
+         tree arg_type = TREE_VALUE (p);
+
+         if (TYPE_READONLY (arg_type) || TYPE_VOLATILE (arg_type))
+           {
+             int quals = TYPE_QUALS (arg_type)
+               & ~TYPE_QUAL_CONST
+               & ~TYPE_QUAL_VOLATILE;
+             TREE_VALUE (p) = build_qualified_type (arg_type, quals);
+             if (!fld->pset.add (TREE_VALUE (p)))
+               free_lang_data_in_type (TREE_VALUE (p), fld);
+           }
+         /* C++ FE uses TREE_PURPOSE to store initial values.  */
+         TREE_PURPOSE (p) = NULL;
+       }
+    }
+  else if (TREE_CODE (type) == METHOD_TYPE)
+    {
+      TREE_TYPE (type) = fld_simplified_type (TREE_TYPE (type), fld);
+      for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
+       {
+         /* C++ FE uses TREE_PURPOSE to store initial values.  */
+         TREE_VALUE (p) = fld_simplified_type (TREE_VALUE (p), fld);
+         TREE_PURPOSE (p) = NULL;
+       }
+    }
+  else if (RECORD_OR_UNION_TYPE_P (type))
+    {
+      /* Remove members that are not FIELD_DECLs from the field list
+        of an aggregate.  These occur in C++.  */
+      for (tree *prev = &TYPE_FIELDS (type), member; (member = *prev);)
+       if (TREE_CODE (member) == FIELD_DECL)
+         prev = &DECL_CHAIN (member);
+       else
+         *prev = DECL_CHAIN (member);
+
+      TYPE_VFIELD (type) = NULL_TREE;
+
+      if (TYPE_BINFO (type))
+       {
+         free_lang_data_in_binfo (TYPE_BINFO (type));
+         /* We need to preserve link to bases and virtual table for all
+            polymorphic types to make devirtualization machinery working.  */
+         if (!BINFO_VTABLE (TYPE_BINFO (type)))
+           TYPE_BINFO (type) = NULL;
+       }
+    }
+  else if (INTEGRAL_TYPE_P (type)
+          || SCALAR_FLOAT_TYPE_P (type)
+          || FIXED_POINT_TYPE_P (type))
+    {
+      if (TREE_CODE (type) == ENUMERAL_TYPE)
+       {
+         ENUM_IS_OPAQUE (type) = 0;
+         ENUM_IS_SCOPED (type) = 0;
+         /* Type values are used only for C++ ODR checking.  Drop them
+            for all type variants and non-ODR types.
+            For ODR types the data is freed in free_odr_warning_data.  */
+         if (!TYPE_VALUES (type))
+           ;
+         else if (TYPE_MAIN_VARIANT (type) != type
+                  || !type_with_linkage_p (type)
+                  || type_in_anonymous_namespace_p (type))
+           TYPE_VALUES (type) = NULL;
+         else
+           register_odr_enum (type);
+       }
+      free_lang_data_in_one_sizepos (&TYPE_MIN_VALUE (type));
+      free_lang_data_in_one_sizepos (&TYPE_MAX_VALUE (type));
+    }
+
+  TYPE_LANG_SLOT_1 (type) = NULL_TREE;
+
+  free_lang_data_in_one_sizepos (&TYPE_SIZE (type));
+  free_lang_data_in_one_sizepos (&TYPE_SIZE_UNIT (type));
+
+  if (TYPE_CONTEXT (type)
+      && TREE_CODE (TYPE_CONTEXT (type)) == BLOCK)
+    {
+      tree ctx = TYPE_CONTEXT (type);
+      do
+       {
+         ctx = BLOCK_SUPERCONTEXT (ctx);
+       }
+      while (ctx && TREE_CODE (ctx) == BLOCK);
+      TYPE_CONTEXT (type) = ctx;
+    }
+
+  TYPE_STUB_DECL (type) = NULL;
+  TYPE_NAME (type) = fld_simplified_type_name (type);
+}
+
+/* Reset all language specific information still present in symbol
+   DECL.  */
+
+static void
+free_lang_data_in_decl (tree decl, class free_lang_data_d *fld)
+{
+  gcc_assert (DECL_P (decl));
+
+  /* Give the FE a chance to remove its own data first.  */
+  lang_hooks.free_lang_data (decl);
+
+  TREE_LANG_FLAG_0 (decl) = 0;
+  TREE_LANG_FLAG_1 (decl) = 0;
+  TREE_LANG_FLAG_2 (decl) = 0;
+  TREE_LANG_FLAG_3 (decl) = 0;
+  TREE_LANG_FLAG_4 (decl) = 0;
+  TREE_LANG_FLAG_5 (decl) = 0;
+  TREE_LANG_FLAG_6 (decl) = 0;
+
+  free_lang_data_in_one_sizepos (&DECL_SIZE (decl));
+  free_lang_data_in_one_sizepos (&DECL_SIZE_UNIT (decl));
+  if (TREE_CODE (decl) == FIELD_DECL)
+    {
+      DECL_FCONTEXT (decl) = NULL;
+      free_lang_data_in_one_sizepos (&DECL_FIELD_OFFSET (decl));
+      if (TREE_CODE (DECL_CONTEXT (decl)) == QUAL_UNION_TYPE)
+       DECL_QUALIFIER (decl) = NULL_TREE;
+    }
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      struct cgraph_node *node;
+      /* Frontends do not set TREE_ADDRESSABLE on public variables even though
+        the address may be taken in other unit, so this flag has no practical
+        use for middle-end.
+
+        It would make more sense if frontends set TREE_ADDRESSABLE to 0 only
+        for public objects that indeed cannot be adressed, but it is not
+        the case.  Set the flag to true so we do not get merge failures for
+        i.e. virtual tables between units that take address of it and
+        units that don't.  */
+      if (TREE_PUBLIC (decl))
+       TREE_ADDRESSABLE (decl) = true;
+      TREE_TYPE (decl) = fld_simplified_type (TREE_TYPE (decl), fld);
+      if (!(node = cgraph_node::get (decl))
+         || (!node->definition && !node->clones))
+       {
+         if (node && !node->declare_variant_alt)
+           node->release_body ();
+         else
+           {
+             release_function_body (decl);
+             DECL_ARGUMENTS (decl) = NULL;
+             DECL_RESULT (decl) = NULL;
+             DECL_INITIAL (decl) = error_mark_node;
+           }
+       }
+      if (gimple_has_body_p (decl) || (node && node->thunk))
+       {
+         tree t;
+
+         /* If DECL has a gimple body, then the context for its
+            arguments must be DECL.  Otherwise, it doesn't really
+            matter, as we will not be emitting any code for DECL.  In
+            general, there may be other instances of DECL created by
+            the front end and since PARM_DECLs are generally shared,
+            their DECL_CONTEXT changes as the replicas of DECL are
+            created.  The only time where DECL_CONTEXT is important
+            is for the FUNCTION_DECLs that have a gimple body (since
+            the PARM_DECL will be used in the function's body).  */
+         for (t = DECL_ARGUMENTS (decl); t; t = TREE_CHAIN (t))
+           DECL_CONTEXT (t) = decl;
+         if (!DECL_FUNCTION_SPECIFIC_TARGET (decl))
+           DECL_FUNCTION_SPECIFIC_TARGET (decl)
+             = target_option_default_node;
+         if (!DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))
+           DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl)
+             = optimization_default_node;
+       }
+
+      /* DECL_SAVED_TREE holds the GENERIC representation for DECL.
+        At this point, it is not needed anymore.  */
+      DECL_SAVED_TREE (decl) = NULL_TREE;
+
+      /* Clear the abstract origin if it refers to a method.
+         Otherwise dwarf2out.c will ICE as we splice functions out of
+         TYPE_FIELDS and thus the origin will not be output
+         correctly.  */
+      if (DECL_ABSTRACT_ORIGIN (decl)
+         && DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))
+         && RECORD_OR_UNION_TYPE_P
+         (DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))))
+       DECL_ABSTRACT_ORIGIN (decl) = NULL_TREE;
+
+      DECL_VINDEX (decl) = NULL_TREE;
+    }
+  else if (VAR_P (decl))
+    {
+      /* See comment above why we set the flag for functions.  */
+      if (TREE_PUBLIC (decl))
+       TREE_ADDRESSABLE (decl) = true;
+      if ((DECL_EXTERNAL (decl)
+          && (!TREE_STATIC (decl) || !TREE_READONLY (decl)))
+         || (decl_function_context (decl) && !TREE_STATIC (decl)))
+       DECL_INITIAL (decl) = NULL_TREE;
+    }
+  else if (TREE_CODE (decl) == TYPE_DECL)
+    {
+      DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (decl) = 0;
+      TREE_PUBLIC (decl) = 0;
+      TREE_PRIVATE (decl) = 0;
+      DECL_ARTIFICIAL (decl) = 0;
+      TYPE_DECL_SUPPRESS_DEBUG (decl) = 0;
+      DECL_INITIAL (decl) = NULL_TREE;
+      DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
+      DECL_MODE (decl) = VOIDmode;
+      SET_DECL_ALIGN (decl, 0);
+      /* TREE_TYPE is cleared at WPA time in free_odr_warning_data.  */
+    }
+  else if (TREE_CODE (decl) == FIELD_DECL)
+    {
+      TREE_TYPE (decl) = fld_simplified_type (TREE_TYPE (decl), fld);
+      DECL_INITIAL (decl) = NULL_TREE;
+    }
+  else if (TREE_CODE (decl) == TRANSLATION_UNIT_DECL
+           && DECL_INITIAL (decl)
+           && TREE_CODE (DECL_INITIAL (decl)) == BLOCK)
+    {
+      /* Strip builtins from the translation-unit BLOCK.  We still have targets
+        without builtin_decl_explicit support and also builtins are shared
+        nodes and thus we can't use TREE_CHAIN in multiple lists.  */
+      tree *nextp = &BLOCK_VARS (DECL_INITIAL (decl));
+      while (*nextp)
+       {
+         tree var = *nextp;
+         if (TREE_CODE (var) == FUNCTION_DECL
+             && fndecl_built_in_p (var))
+           *nextp = TREE_CHAIN (var);
+         else
+           nextp = &TREE_CHAIN (var);
+        }
+    }
+  /* We need to keep field decls associated with their trees. Otherwise tree
+     merging may merge some fileds and keep others disjoint wich in turn will
+     not do well with TREE_CHAIN pointers linking them.
+
+     Also do not drop containing types for virtual methods and tables because
+     these are needed by devirtualization.
+     C++ destructors are special because C++ frontends sometimes produces
+     virtual destructor as an alias of non-virtual destructor.  In
+     devirutalization code we always walk through aliases and we need
+     context to be preserved too.  See PR89335  */
+  if (TREE_CODE (decl) != FIELD_DECL
+      && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+          || (!DECL_VIRTUAL_P (decl)
+             && (TREE_CODE (decl) != FUNCTION_DECL
+                 || !DECL_CXX_DESTRUCTOR_P (decl)))))
+    DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl));
+}
+
+
+/* Operand callback helper for free_lang_data_in_node.  *TP is the
+   subtree operand being considered.  */
+
+static tree
+find_decls_types_r (tree *tp, int *ws, void *data)
+{
+  tree t = *tp;
+  class free_lang_data_d *fld = (class free_lang_data_d *) data;
+
+  if (TREE_CODE (t) == TREE_LIST)
+    return NULL_TREE;
+
+  /* Language specific nodes will be removed, so there is no need
+     to gather anything under them.  */
+  if (is_lang_specific (t))
+    {
+      *ws = 0;
+      return NULL_TREE;
+    }
+
+  if (DECL_P (t))
+    {
+      /* Note that walk_tree does not traverse every possible field in
+        decls, so we have to do our own traversals here.  */
+      add_tree_to_fld_list (t, fld);
+
+      fld_worklist_push (DECL_NAME (t), fld);
+      fld_worklist_push (DECL_CONTEXT (t), fld);
+      fld_worklist_push (DECL_SIZE (t), fld);
+      fld_worklist_push (DECL_SIZE_UNIT (t), fld);
+
+      /* We are going to remove everything under DECL_INITIAL for
+        TYPE_DECLs.  No point walking them.  */
+      if (TREE_CODE (t) != TYPE_DECL)
+       fld_worklist_push (DECL_INITIAL (t), fld);
+
+      fld_worklist_push (DECL_ATTRIBUTES (t), fld);
+      fld_worklist_push (DECL_ABSTRACT_ORIGIN (t), fld);
+
+      if (TREE_CODE (t) == FUNCTION_DECL)
+       {
+         fld_worklist_push (DECL_ARGUMENTS (t), fld);
+         fld_worklist_push (DECL_RESULT (t), fld);
+       }
+      else if (TREE_CODE (t) == FIELD_DECL)
+       {
+         fld_worklist_push (DECL_FIELD_OFFSET (t), fld);
+         fld_worklist_push (DECL_BIT_FIELD_TYPE (t), fld);
+         fld_worklist_push (DECL_FIELD_BIT_OFFSET (t), fld);
+         fld_worklist_push (DECL_FCONTEXT (t), fld);
+       }
+
+      if ((VAR_P (t) || TREE_CODE (t) == PARM_DECL)
+         && DECL_HAS_VALUE_EXPR_P (t))
+       fld_worklist_push (DECL_VALUE_EXPR (t), fld);
+
+      if (TREE_CODE (t) != FIELD_DECL
+         && TREE_CODE (t) != TYPE_DECL)
+       fld_worklist_push (TREE_CHAIN (t), fld);
+      *ws = 0;
+    }
+  else if (TYPE_P (t))
+    {
+      /* Note that walk_tree does not traverse every possible field in
+        types, so we have to do our own traversals here.  */
+      add_tree_to_fld_list (t, fld);
+
+      if (!RECORD_OR_UNION_TYPE_P (t))
+       fld_worklist_push (TYPE_CACHED_VALUES (t), fld);
+      fld_worklist_push (TYPE_SIZE (t), fld);
+      fld_worklist_push (TYPE_SIZE_UNIT (t), fld);
+      fld_worklist_push (TYPE_ATTRIBUTES (t), fld);
+      fld_worklist_push (TYPE_POINTER_TO (t), fld);
+      fld_worklist_push (TYPE_REFERENCE_TO (t), fld);
+      fld_worklist_push (TYPE_NAME (t), fld);
+      /* While we do not stream TYPE_POINTER_TO and TYPE_REFERENCE_TO
+        lists, we may look types up in these lists and use them while
+        optimizing the function body.  Thus we need to free lang data
+        in them.  */
+      if (TREE_CODE (t) == POINTER_TYPE)
+       fld_worklist_push (TYPE_NEXT_PTR_TO (t), fld);
+      if (TREE_CODE (t) == REFERENCE_TYPE)
+       fld_worklist_push (TYPE_NEXT_REF_TO (t), fld);
+      if (!POINTER_TYPE_P (t))
+       fld_worklist_push (TYPE_MIN_VALUE_RAW (t), fld);
+      /* TYPE_MAX_VALUE_RAW is TYPE_BINFO for record types.  */
+      if (!RECORD_OR_UNION_TYPE_P (t))
+       fld_worklist_push (TYPE_MAX_VALUE_RAW (t), fld);
+      fld_worklist_push (TYPE_MAIN_VARIANT (t), fld);
+      /* Do not walk TYPE_NEXT_VARIANT.  We do not stream it and thus
+        do not and want not to reach unused variants this way.  */
+      if (TYPE_CONTEXT (t))
+       {
+         tree ctx = TYPE_CONTEXT (t);
+         /* We adjust BLOCK TYPE_CONTEXTs to the innermost non-BLOCK one.
+            So push that instead.  */
+         while (ctx && TREE_CODE (ctx) == BLOCK)
+           ctx = BLOCK_SUPERCONTEXT (ctx);
+         fld_worklist_push (ctx, fld);
+       }
+      fld_worklist_push (TYPE_CANONICAL (t), fld);
+
+      if (RECORD_OR_UNION_TYPE_P (t) && TYPE_BINFO (t))
+       {
+         unsigned i;
+         tree tem;
+         FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (TYPE_BINFO (t)), i, tem)
+           fld_worklist_push (TREE_TYPE (tem), fld);
+         fld_worklist_push (BINFO_TYPE (TYPE_BINFO (t)), fld);
+         fld_worklist_push (BINFO_VTABLE (TYPE_BINFO (t)), fld);
+       }
+      if (RECORD_OR_UNION_TYPE_P (t))
+       {
+         tree tem;
+         /* Push all TYPE_FIELDS - there can be interleaving interesting
+            and non-interesting things.  */
+         tem = TYPE_FIELDS (t);
+         while (tem)
+           {
+             if (TREE_CODE (tem) == FIELD_DECL)
+               fld_worklist_push (tem, fld);
+             tem = TREE_CHAIN (tem);
+           }
+       }
+      if (FUNC_OR_METHOD_TYPE_P (t))
+       fld_worklist_push (TYPE_METHOD_BASETYPE (t), fld);
+
+      fld_worklist_push (TYPE_STUB_DECL (t), fld);
+      *ws = 0;
+    }
+  else if (TREE_CODE (t) == BLOCK)
+    {
+      for (tree *tem = &BLOCK_VARS (t); *tem; )
+       {
+         if (TREE_CODE (*tem) != LABEL_DECL
+             && (TREE_CODE (*tem) != VAR_DECL
+                 || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem))))
+           {
+             gcc_assert (TREE_CODE (*tem) != RESULT_DECL
+                         && TREE_CODE (*tem) != PARM_DECL);
+             *tem = TREE_CHAIN (*tem);
+           }
+         else
+           {
+             fld_worklist_push (*tem, fld);
+             tem = &TREE_CHAIN (*tem);
+           }
+       }
+      for (tree tem = BLOCK_SUBBLOCKS (t); tem; tem = BLOCK_CHAIN (tem))
+       fld_worklist_push (tem, fld);
+      fld_worklist_push (BLOCK_ABSTRACT_ORIGIN (t), fld);
+    }
+
+  if (TREE_CODE (t) != IDENTIFIER_NODE
+      && CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPED))
+    fld_worklist_push (TREE_TYPE (t), fld);
+
+  return NULL_TREE;
+}
+
+
+/* Find decls and types in T.  */
+
+static void
+find_decls_types (tree t, class free_lang_data_d *fld)
+{
+  while (1)
+    {
+      if (!fld->pset.contains (t))
+       walk_tree (&t, find_decls_types_r, fld, &fld->pset);
+      if (fld->worklist.is_empty ())
+       break;
+      t = fld->worklist.pop ();
+    }
+}
+
+/* Translate all the types in LIST with the corresponding runtime
+   types.  */
+
+static tree
+get_eh_types_for_runtime (tree list)
+{
+  tree head, prev;
+
+  if (list == NULL_TREE)
+    return NULL_TREE;
+
+  head = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list)));
+  prev = head;
+  list = TREE_CHAIN (list);
+  while (list)
+    {
+      tree n = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list)));
+      TREE_CHAIN (prev) = n;
+      prev = TREE_CHAIN (prev);
+      list = TREE_CHAIN (list);
+    }
+
+  return head;
+}
+
+
+/* Find decls and types referenced in EH region R and store them in
+   FLD->DECLS and FLD->TYPES.  */
+
+static void
+find_decls_types_in_eh_region (eh_region r, class free_lang_data_d *fld)
+{
+  switch (r->type)
+    {
+    case ERT_CLEANUP:
+      break;
+
+    case ERT_TRY:
+      {
+       eh_catch c;
+
+       /* The types referenced in each catch must first be changed to the
+          EH types used at runtime.  This removes references to FE types
+          in the region.  */
+       for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+         {
+           c->type_list = get_eh_types_for_runtime (c->type_list);
+           walk_tree (&c->type_list, find_decls_types_r, fld, &fld->pset);
+         }
+      }
+      break;
+
+    case ERT_ALLOWED_EXCEPTIONS:
+      r->u.allowed.type_list
+       = get_eh_types_for_runtime (r->u.allowed.type_list);
+      walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, &fld->pset);
+      break;
+
+    case ERT_MUST_NOT_THROW:
+      walk_tree (&r->u.must_not_throw.failure_decl,
+                find_decls_types_r, fld, &fld->pset);
+      break;
+    }
+}
+
+
+/* Find decls and types referenced in cgraph node N and store them in
+   FLD->DECLS and FLD->TYPES.  Unlike pass_referenced_vars, this will
+   look for *every* kind of DECL and TYPE node reachable from N,
+   including those embedded inside types and decls (i.e,, TYPE_DECLs,
+   NAMESPACE_DECLs, etc).  */
+
+static void
+find_decls_types_in_node (struct cgraph_node *n, class free_lang_data_d *fld)
+{
+  basic_block bb;
+  struct function *fn;
+  unsigned ix;
+  tree t;
+
+  find_decls_types (n->decl, fld);
+
+  if (!gimple_has_body_p (n->decl))
+    return;
+
+  gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
+
+  fn = DECL_STRUCT_FUNCTION (n->decl);
+
+  /* Traverse locals. */
+  FOR_EACH_LOCAL_DECL (fn, ix, t)
+    find_decls_types (t, fld);
+
+  /* Traverse EH regions in FN.  */
+  {
+    eh_region r;
+    FOR_ALL_EH_REGION_FN (r, fn)
+      find_decls_types_in_eh_region (r, fld);
+  }
+
+  /* Traverse every statement in FN.  */
+  FOR_EACH_BB_FN (bb, fn)
+    {
+      gphi_iterator psi;
+      gimple_stmt_iterator si;
+      unsigned i;
+
+      for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
+       {
+         gphi *phi = psi.phi ();
+
+         for (i = 0; i < gimple_phi_num_args (phi); i++)
+           {
+             tree *arg_p = gimple_phi_arg_def_ptr (phi, i);
+             find_decls_types (*arg_p, fld);
+           }
+       }
+
+      for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+       {
+         gimple *stmt = gsi_stmt (si);
+
+         if (is_gimple_call (stmt))
+           find_decls_types (gimple_call_fntype (stmt), fld);
+
+         for (i = 0; i < gimple_num_ops (stmt); i++)
+           {
+             tree arg = gimple_op (stmt, i);
+             find_decls_types (arg, fld);
+             /* find_decls_types doesn't walk TREE_PURPOSE of TREE_LISTs,
+                which we need for asm stmts.  */
+             if (arg
+                 && TREE_CODE (arg) == TREE_LIST
+                 && TREE_PURPOSE (arg)
+                 && gimple_code (stmt) == GIMPLE_ASM)
+               find_decls_types (TREE_PURPOSE (arg), fld);
+           }
+       }
+    }
+}
+
+
+/* Find decls and types referenced in varpool node N and store them in
+   FLD->DECLS and FLD->TYPES.  Unlike pass_referenced_vars, this will
+   look for *every* kind of DECL and TYPE node reachable from N,
+   including those embedded inside types and decls (i.e,, TYPE_DECLs,
+   NAMESPACE_DECLs, etc).  */
+
+static void
+find_decls_types_in_var (varpool_node *v, class free_lang_data_d *fld)
+{
+  find_decls_types (v->decl, fld);
+}
+
+/* Free language specific information for every operand and expression
+   in every node of the call graph.  This process operates in three stages:
+
+   1- Every callgraph node and varpool node is traversed looking for
+   decls and types embedded in them.  This is a more exhaustive
+   search than that done by find_referenced_vars, because it will
+   also collect individual fields, decls embedded in types, etc.
+
+   2- All the decls found are sent to free_lang_data_in_decl.
+
+   3- All the types found are sent to free_lang_data_in_type.
+
+   The ordering between decls and types is important because
+   free_lang_data_in_decl sets assembler names, which includes
+   mangling.  So types cannot be freed up until assembler names have
+   been set up.  */
+
+static void
+free_lang_data_in_cgraph (class free_lang_data_d *fld)
+{
+  struct cgraph_node *n;
+  varpool_node *v;
+  tree t;
+  unsigned i;
+  alias_pair *p;
+
+  /* Find decls and types in the body of every function in the callgraph.  */
+  FOR_EACH_FUNCTION (n)
+    find_decls_types_in_node (n, fld);
+
+  FOR_EACH_VEC_SAFE_ELT (alias_pairs, i, p)
+    find_decls_types (p->decl, fld);
+
+  /* Find decls and types in every varpool symbol.  */
+  FOR_EACH_VARIABLE (v)
+    find_decls_types_in_var (v, fld);
+
+  /* Set the assembler name on every decl found.  We need to do this
+     now because free_lang_data_in_decl will invalidate data needed
+     for mangling.  This breaks mangling on interdependent decls.  */
+  FOR_EACH_VEC_ELT (fld->decls, i, t)
+    assign_assembler_name_if_needed (t);
+
+  /* Traverse every decl found freeing its language data.  */
+  FOR_EACH_VEC_ELT (fld->decls, i, t)
+    free_lang_data_in_decl (t, fld);
+
+  /* Traverse every type found freeing its language data.  */
+  FOR_EACH_VEC_ELT (fld->types, i, t)
+    free_lang_data_in_type (t, fld);
+}
+
+
+/* Free resources that are used by FE but are not needed once they are done. */
+
+static unsigned
+free_lang_data (void)
+{
+  unsigned i;
+  class free_lang_data_d fld;
+
+  /* If we are the LTO frontend we have freed lang-specific data already.  */
+  if (in_lto_p
+      || (!flag_generate_lto && !flag_generate_offload))
+    {
+      /* Rebuild type inheritance graph even when not doing LTO to get
+        consistent profile data.  */
+      rebuild_type_inheritance_graph ();
+      return 0;
+    }
+
+  fld_incomplete_types = new hash_map<tree, tree>;
+  fld_simplified_types = new hash_map<tree, tree>;
+
+  /* Provide a dummy TRANSLATION_UNIT_DECL if the FE failed to provide one.  */
+  if (vec_safe_is_empty (all_translation_units))
+    build_translation_unit_decl (NULL_TREE);
+
+  /* Allocate and assign alias sets to the standard integer types
+     while the slots are still in the way the frontends generated them.  */
+  for (i = 0; i < itk_none; ++i)
+    if (integer_types[i])
+      TYPE_ALIAS_SET (integer_types[i]) = get_alias_set (integer_types[i]);
+
+  /* Traverse the IL resetting language specific information for
+     operands, expressions, etc.  */
+  free_lang_data_in_cgraph (&fld);
+
+  /* Create gimple variants for common types.  */
+  for (unsigned i = 0;
+       i < sizeof (builtin_structptr_types) / sizeof (builtin_structptr_type);
+       ++i)
+    builtin_structptr_types[i].node = builtin_structptr_types[i].base;
+
+  /* Reset some langhooks.  Do not reset types_compatible_p, it may
+     still be used indirectly via the get_alias_set langhook.  */
+  lang_hooks.dwarf_name = lhd_dwarf_name;
+  lang_hooks.decl_printable_name = gimple_decl_printable_name;
+  lang_hooks.gimplify_expr = lhd_gimplify_expr;
+  lang_hooks.overwrite_decl_assembler_name = lhd_overwrite_decl_assembler_name;
+  lang_hooks.print_xnode = lhd_print_tree_nothing;
+  lang_hooks.print_decl = lhd_print_tree_nothing;
+  lang_hooks.print_type = lhd_print_tree_nothing;
+  lang_hooks.print_identifier = lhd_print_tree_nothing;
+
+  lang_hooks.tree_inlining.var_mod_type_p = hook_bool_tree_tree_false;
+
+  if (flag_checking)
+    {
+      int i;
+      tree t;
+
+      FOR_EACH_VEC_ELT (fld.types, i, t)
+       verify_type (t);
+    }
+
+  /* We do not want the default decl_assembler_name implementation,
+     rather if we have fixed everything we want a wrapper around it
+     asserting that all non-local symbols already got their assembler
+     name and only produce assembler names for local symbols.  Or rather
+     make sure we never call decl_assembler_name on local symbols and
+     devise a separate, middle-end private scheme for it.  */
+
+  /* Reset diagnostic machinery.  */
+  tree_diagnostics_defaults (global_dc);
+
+  rebuild_type_inheritance_graph ();
+
+  delete fld_incomplete_types;
+  delete fld_simplified_types;
+
+  return 0;
+}
+
+const pass_data pass_data_ipa_free_lang_data =
+  {
+   SIMPLE_IPA_PASS, /* type */
+   "*free_lang_data", /* name */
+   OPTGROUP_NONE, /* optinfo_flags */
+   TV_IPA_FREE_LANG_DATA, /* tv_id */
+   0, /* properties_required */
+   0, /* properties_provided */
+   0, /* properties_destroyed */
+   0, /* todo_flags_start */
+   0, /* todo_flags_finish */
+  };
+
+class pass_ipa_free_lang_data : public simple_ipa_opt_pass
+{
+public:
+  pass_ipa_free_lang_data (gcc::context *ctxt)
+    : simple_ipa_opt_pass (pass_data_ipa_free_lang_data, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *) { return free_lang_data (); }
+
+}; // class pass_ipa_free_lang_data
+
+} // anon namespace
+
+simple_ipa_opt_pass *
+make_pass_ipa_free_lang_data (gcc::context *ctxt)
+{
+  return new pass_ipa_free_lang_data (ctxt);
+}
index 6129d911ee6d2b690c2127b782552c687b1bdd4a..c5506a005bbfc9f6ac2dac389a3f02787dd9a3d2 100644 (file)
@@ -266,8 +266,6 @@ static void print_type_hash_statistics (void);
 static void print_debug_expr_statistics (void);
 static void print_value_expr_statistics (void);
 
-static tree build_array_type_1 (tree, tree, bool, bool, bool);
-
 tree global_trees[TI_MAX];
 tree integer_types[itk_none];
 
@@ -722,6 +720,112 @@ overwrite_decl_assembler_name (tree decl, tree name)
     lang_hooks.overwrite_decl_assembler_name (decl, name);
 }
 
+/* Return true if DECL may need an assembler name to be set.  */
+
+static inline bool
+need_assembler_name_p (tree decl)
+{
+  /* We use DECL_ASSEMBLER_NAME to hold mangled type names for One Definition
+     Rule merging.  This makes type_odr_p to return true on those types during
+     LTO and by comparing the mangled name, we can say what types are intended
+     to be equivalent across compilation unit.
+
+     We do not store names of type_in_anonymous_namespace_p.
+
+     Record, union and enumeration type have linkage that allows use
+     to check type_in_anonymous_namespace_p. We do not mangle compound types
+     that always can be compared structurally.
+
+     Similarly for builtin types, we compare properties of their main variant.
+     A special case are integer types where mangling do make differences
+     between char/signed char/unsigned char etc.  Storing name for these makes
+     e.g.  -fno-signed-char/-fsigned-char mismatches to be handled well.
+     See cp/mangle.c:write_builtin_type for details.  */
+
+  if (TREE_CODE (decl) == TYPE_DECL)
+    {
+      if (DECL_NAME (decl)
+         && decl == TYPE_NAME (TREE_TYPE (decl))
+         && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TREE_TYPE (decl)
+         && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
+         && ((TREE_CODE (TREE_TYPE (decl)) != RECORD_TYPE
+              && TREE_CODE (TREE_TYPE (decl)) != UNION_TYPE)
+             || TYPE_CXX_ODR_P (TREE_TYPE (decl)))
+         && (type_with_linkage_p (TREE_TYPE (decl))
+             || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
+         && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+       return !DECL_ASSEMBLER_NAME_SET_P (decl);
+      return false;
+    }
+  /* Only FUNCTION_DECLs and VAR_DECLs are considered.  */
+  if (!VAR_OR_FUNCTION_DECL_P (decl))
+    return false;
+
+  /* If DECL already has its assembler name set, it does not need a
+     new one.  */
+  if (!HAS_DECL_ASSEMBLER_NAME_P (decl)
+      || DECL_ASSEMBLER_NAME_SET_P (decl))
+    return false;
+
+  /* Abstract decls do not need an assembler name.  */
+  if (DECL_ABSTRACT_P (decl))
+    return false;
+
+  /* For VAR_DECLs, only static, public and external symbols need an
+     assembler name.  */
+  if (VAR_P (decl)
+      && !TREE_STATIC (decl)
+      && !TREE_PUBLIC (decl)
+      && !DECL_EXTERNAL (decl))
+    return false;
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      /* Do not set assembler name on builtins.  Allow RTL expansion to
+        decide whether to expand inline or via a regular call.  */
+      if (fndecl_built_in_p (decl)
+         && DECL_BUILT_IN_CLASS (decl) != BUILT_IN_FRONTEND)
+       return false;
+
+      /* Functions represented in the callgraph need an assembler name.  */
+      if (cgraph_node::get (decl) != NULL)
+       return true;
+
+      /* Unused and not public functions don't need an assembler name.  */
+      if (!TREE_USED (decl) && !TREE_PUBLIC (decl))
+       return false;
+    }
+
+  return true;
+}
+
+/* If T needs an assembler name, have one created for it.  */
+
+void
+assign_assembler_name_if_needed (tree t)
+{
+  if (need_assembler_name_p (t))
+    {
+      /* When setting DECL_ASSEMBLER_NAME, the C++ mangler may emit
+        diagnostics that use input_location to show locus
+        information.  The problem here is that, at this point,
+        input_location is generally anchored to the end of the file
+        (since the parser is long gone), so we don't have a good
+        position to pin it to.
+
+        To alleviate this problem, this uses the location of T's
+        declaration.  Examples of this are
+        testsuite/g++.dg/template/cond2.C and
+        testsuite/g++.dg/template/pr35240.C.  */
+      location_t saved_location = input_location;
+      input_location = DECL_SOURCE_LOCATION (t);
+
+      decl_assembler_name (t);
+
+      input_location = saved_location;
+    }
+}
+
 /* When the target supports COMDAT groups, this indicates which group the
    DECL is associated with.  This can be either an IDENTIFIER_NODE or a
    decl, in which case its DECL_ASSEMBLER_NAME identifies the group.  */
@@ -5245,1365 +5349,117 @@ protected_set_expr_location_if_unset (tree t, location_t loc)
   if (t && !EXPR_HAS_LOCATION (t))
     protected_set_expr_location (t, loc);
 }
-
-/* Data used when collecting DECLs and TYPEs for language data removal.  */
-
-class free_lang_data_d
-{
-public:
-  free_lang_data_d () : decls (100), types (100) {}
-
-  /* Worklist to avoid excessive recursion.  */
-  auto_vec<tree> worklist;
-
-  /* Set of traversed objects.  Used to avoid duplicate visits.  */
-  hash_set<tree> pset;
-
-  /* Array of symbols to process with free_lang_data_in_decl.  */
-  auto_vec<tree> decls;
-
-  /* Array of types to process with free_lang_data_in_type.  */
-  auto_vec<tree> types;
-};
-
-
-/* Add type or decl T to one of the list of tree nodes that need their
-   language data removed.  The lists are held inside FLD.  */
+\f
+/* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
+   of the various TYPE_QUAL values.  */
 
 static void
-add_tree_to_fld_list (tree t, class free_lang_data_d *fld)
+set_type_quals (tree type, int type_quals)
 {
-  if (DECL_P (t))
-    fld->decls.safe_push (t);
-  else if (TYPE_P (t))
-    fld->types.safe_push (t);
-  else
-    gcc_unreachable ();
+  TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
+  TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
+  TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
+  TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0;
+  TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
 }
 
-/* Push tree node T into FLD->WORKLIST.  */
+/* Returns true iff CAND and BASE have equivalent language-specific
+   qualifiers.  */
 
-static inline void
-fld_worklist_push (tree t, class free_lang_data_d *fld)
+bool
+check_lang_type (const_tree cand, const_tree base)
 {
-  if (t && !is_lang_specific (t) && !fld->pset.contains (t))
-    fld->worklist.safe_push ((t));
-}
-
-
-\f
-/* Return simplified TYPE_NAME of TYPE.  */
-
-static tree
-fld_simplified_type_name (tree type)
-{
-  if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL)
-    return TYPE_NAME (type);
-  /* Drop TYPE_DECLs in TYPE_NAME in favor of the identifier in the
-     TYPE_DECL if the type doesn't have linkage.
-     this must match fld_  */
-  if (type != TYPE_MAIN_VARIANT (type)
-      || (!DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (type))
-         && (TREE_CODE (type) != RECORD_TYPE
-             || !TYPE_BINFO (type)
-             || !BINFO_VTABLE (TYPE_BINFO (type)))))
-    return DECL_NAME (TYPE_NAME (type));
-  return TYPE_NAME (type);
-}
-
-/* Do same comparsion as check_qualified_type skipping lang part of type
-   and be more permissive about type names: we only care that names are
-   same (for diagnostics) and that ODR names are the same.
-   If INNER_TYPE is non-NULL, be sure that TREE_TYPE match it.  */
-
-static bool
-fld_type_variant_equal_p (tree t, tree v, tree inner_type)
-{
-  if (TYPE_QUALS (t) != TYPE_QUALS (v)
-      /* We want to match incomplete variants with complete types.
-        In this case we need to ignore alignment.   */
-      || ((!RECORD_OR_UNION_TYPE_P (t) || COMPLETE_TYPE_P (v))
-         && (TYPE_ALIGN (t) != TYPE_ALIGN (v)
-             || TYPE_USER_ALIGN (t) != TYPE_USER_ALIGN (v)))
-      || fld_simplified_type_name (t) != fld_simplified_type_name (v)
-      || !attribute_list_equal (TYPE_ATTRIBUTES (t),
-                               TYPE_ATTRIBUTES (v))
-      || (inner_type && TREE_TYPE (v) != inner_type))
-    return false;
-
-  return true;
+  if (lang_hooks.types.type_hash_eq == NULL)
+    return true;
+  /* type_hash_eq currently only applies to these types.  */
+  if (TREE_CODE (cand) != FUNCTION_TYPE
+      && TREE_CODE (cand) != METHOD_TYPE)
+    return true;
+  return lang_hooks.types.type_hash_eq (cand, base);
 }
 
-/* Find variant of FIRST that match T and create new one if necessary.
-   Set TREE_TYPE to INNER_TYPE if non-NULL.  */
+/* This function checks to see if TYPE matches the size one of the built-in 
+   atomic types, and returns that core atomic type.  */
 
 static tree
-fld_type_variant (tree first, tree t, class free_lang_data_d *fld,
-                 tree inner_type = NULL)
+find_atomic_core_type (const_tree type)
 {
-  if (first == TYPE_MAIN_VARIANT (t))
-    return t;
-  for (tree v = first; v; v = TYPE_NEXT_VARIANT (v))
-    if (fld_type_variant_equal_p (t, v, inner_type))
-      return v;
-  tree v = build_variant_type_copy (first);
-  TYPE_READONLY (v) = TYPE_READONLY (t);
-  TYPE_VOLATILE (v) = TYPE_VOLATILE (t);
-  TYPE_ATOMIC (v) = TYPE_ATOMIC (t);
-  TYPE_RESTRICT (v) = TYPE_RESTRICT (t);
-  TYPE_ADDR_SPACE (v) = TYPE_ADDR_SPACE (t);
-  TYPE_NAME (v) = TYPE_NAME (t);
-  TYPE_ATTRIBUTES (v) = TYPE_ATTRIBUTES (t);
-  TYPE_CANONICAL (v) = TYPE_CANONICAL (t);
-  /* Variants of incomplete types should have alignment 
-     set to BITS_PER_UNIT.  Do not copy the actual alignment.  */
-  if (!RECORD_OR_UNION_TYPE_P (v) || COMPLETE_TYPE_P (v))
-    {
-      SET_TYPE_ALIGN (v, TYPE_ALIGN (t));
-      TYPE_USER_ALIGN (v) = TYPE_USER_ALIGN (t);
-    }
-  if (inner_type)
-    TREE_TYPE (v) = inner_type;
-  gcc_checking_assert (fld_type_variant_equal_p (t,v, inner_type));
-  if (!fld->pset.add (v))
-    add_tree_to_fld_list (v, fld);
-  return v;
-}
-
-/* Map complete types to incomplete types.  */
+  tree base_atomic_type;
 
-static hash_map<tree, tree> *fld_incomplete_types;
+  /* Only handle complete types.  */
+  if (!tree_fits_uhwi_p (TYPE_SIZE (type)))
+    return NULL_TREE;
 
-/* Map types to simplified types.  */
+  switch (tree_to_uhwi (TYPE_SIZE (type)))
+    {
+    case 8:
+      base_atomic_type = atomicQI_type_node;
+      break;
 
-static hash_map<tree, tree> *fld_simplified_types;
+    case 16:
+      base_atomic_type = atomicHI_type_node;
+      break;
 
-/* Produce variant of T whose TREE_TYPE is T2. If it is main variant,
-   use MAP to prevent duplicates.  */
+    case 32:
+      base_atomic_type = atomicSI_type_node;
+      break;
 
-static tree
-fld_process_array_type (tree t, tree t2, hash_map<tree, tree> *map,
-                       class free_lang_data_d *fld)
-{
-  if (TREE_TYPE (t) == t2)
-    return t;
+    case 64:
+      base_atomic_type = atomicDI_type_node;
+      break;
 
-  if (TYPE_MAIN_VARIANT (t) != t)
-    {
-      return fld_type_variant
-              (fld_process_array_type (TYPE_MAIN_VARIANT (t),
-                                       TYPE_MAIN_VARIANT (t2), map, fld),
-               t, fld, t2);
-    }
+    case 128:
+      base_atomic_type = atomicTI_type_node;
+      break;
 
-  bool existed;
-  tree &array
-     = map->get_or_insert (t, &existed);
-  if (!existed)
-    {
-      array
-       = build_array_type_1 (t2, TYPE_DOMAIN (t), TYPE_TYPELESS_STORAGE (t),
-                             false, false);
-      TYPE_CANONICAL (array) = TYPE_CANONICAL (t);
-      if (!fld->pset.add (array))
-       add_tree_to_fld_list (array, fld);
+    default:
+      base_atomic_type = NULL_TREE;
     }
-  return array;
-}
 
-/* Return CTX after removal of contexts that are not relevant  */
-
-static tree
-fld_decl_context (tree ctx)
-{
-  /* Variably modified types are needed for tree_is_indexable to decide
-     whether the type needs to go to local or global section.
-     This code is semi-broken but for now it is easiest to keep contexts
-     as expected.  */
-  if (ctx && TYPE_P (ctx)
-      && !variably_modified_type_p (ctx, NULL_TREE))
-     {
-       while (ctx && TYPE_P (ctx))
-        ctx = TYPE_CONTEXT (ctx);
-     }
-  return ctx;
+  return base_atomic_type;
 }
 
-/* For T being aggregate type try to turn it into a incomplete variant.
-   Return T if no simplification is possible.  */
+/* Returns true iff unqualified CAND and BASE are equivalent.  */
 
-static tree
-fld_incomplete_type_of (tree t, class free_lang_data_d *fld)
+bool
+check_base_type (const_tree cand, const_tree base)
 {
-  if (!t)
-    return NULL;
-  if (POINTER_TYPE_P (t))
+  if (TYPE_NAME (cand) != TYPE_NAME (base)
+      /* Apparently this is needed for Objective-C.  */
+      || TYPE_CONTEXT (cand) != TYPE_CONTEXT (base)
+      || !attribute_list_equal (TYPE_ATTRIBUTES (cand),
+                               TYPE_ATTRIBUTES (base)))
+    return false;
+  /* Check alignment.  */
+  if (TYPE_ALIGN (cand) == TYPE_ALIGN (base)
+      && TYPE_USER_ALIGN (cand) == TYPE_USER_ALIGN (base))
+    return true;
+  /* Atomic types increase minimal alignment.  We must to do so as well
+     or we get duplicated canonical types. See PR88686.  */
+  if ((TYPE_QUALS (cand) & TYPE_QUAL_ATOMIC))
     {
-      tree t2 = fld_incomplete_type_of (TREE_TYPE (t), fld);
-      if (t2 != TREE_TYPE (t))
-       {
-         tree first;
-         if (TREE_CODE (t) == POINTER_TYPE)
-           first = build_pointer_type_for_mode (t2, TYPE_MODE (t),
-                                               TYPE_REF_CAN_ALIAS_ALL (t));
-         else
-           first = build_reference_type_for_mode (t2, TYPE_MODE (t),
-                                               TYPE_REF_CAN_ALIAS_ALL (t));
-         gcc_assert (TYPE_CANONICAL (t2) != t2
-                     && TYPE_CANONICAL (t2) == TYPE_CANONICAL (TREE_TYPE (t)));
-         if (!fld->pset.add (first))
-           add_tree_to_fld_list (first, fld);
-         return fld_type_variant (first, t, fld);
-       }
-      return t;
+      /* See if this object can map to a basic atomic type.  */
+      tree atomic_type = find_atomic_core_type (cand);
+      if (atomic_type && TYPE_ALIGN (atomic_type) == TYPE_ALIGN (cand))
+       return true;
     }
-  if (TREE_CODE (t) == ARRAY_TYPE)
-    return fld_process_array_type (t,
-                                  fld_incomplete_type_of (TREE_TYPE (t), fld),
-                                  fld_incomplete_types, fld);
-  if ((!RECORD_OR_UNION_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE)
-      || !COMPLETE_TYPE_P (t))
-    return t;
-  if (TYPE_MAIN_VARIANT (t) == t)
-    {
-      bool existed;
-      tree &copy
-        = fld_incomplete_types->get_or_insert (t, &existed);
-
-      if (!existed)
-       {
-         copy = build_distinct_type_copy (t);
-
-         /* It is possible that type was not seen by free_lang_data yet.  */
-         if (!fld->pset.add (copy))
-           add_tree_to_fld_list (copy, fld);
-         TYPE_SIZE (copy) = NULL;
-         TYPE_USER_ALIGN (copy) = 0;
-         TYPE_SIZE_UNIT (copy) = NULL;
-         TYPE_CANONICAL (copy) = TYPE_CANONICAL (t);
-         TREE_ADDRESSABLE (copy) = 0;
-         if (AGGREGATE_TYPE_P (t))
-           {
-             SET_TYPE_MODE (copy, VOIDmode);
-             SET_TYPE_ALIGN (copy, BITS_PER_UNIT);
-             TYPE_TYPELESS_STORAGE (copy) = 0;
-             TYPE_FIELDS (copy) = NULL;
-             TYPE_BINFO (copy) = NULL;
-             TYPE_FINAL_P (copy) = 0;
-             TYPE_EMPTY_P (copy) = 0;
-           }
-         else
-           {
-             TYPE_VALUES (copy) = NULL;
-             ENUM_IS_OPAQUE (copy) = 0;
-             ENUM_IS_SCOPED (copy) = 0;
-           }
-
-         /* Build copy of TYPE_DECL in TYPE_NAME if necessary.
-            This is needed for ODR violation warnings to come out right (we
-            want duplicate TYPE_DECLs whenever the type is duplicated because
-            of ODR violation.  Because lang data in the TYPE_DECL may not
-            have been freed yet, rebuild it from scratch and copy relevant
-            fields.  */
-         TYPE_NAME (copy) = fld_simplified_type_name (copy);
-         tree name = TYPE_NAME (copy);
-
-         if (name && TREE_CODE (name) == TYPE_DECL)
-           {
-             gcc_checking_assert (TREE_TYPE (name) == t);
-             tree name2 = build_decl (DECL_SOURCE_LOCATION (name), TYPE_DECL,
-                                      DECL_NAME (name), copy);
-             if (DECL_ASSEMBLER_NAME_SET_P (name))
-               SET_DECL_ASSEMBLER_NAME (name2, DECL_ASSEMBLER_NAME (name));
-             SET_DECL_ALIGN (name2, 0);
-             DECL_CONTEXT (name2) = fld_decl_context
-                                        (DECL_CONTEXT (name));
-             TYPE_NAME (copy) = name2;
-           }
-       }
-      return copy;
-   }
-  return (fld_type_variant
-           (fld_incomplete_type_of (TYPE_MAIN_VARIANT (t), fld), t, fld));
+  return false;
 }
 
-/* Simplify type T for scenarios where we do not need complete pointer
-   types.  */
+/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS.  */
 
-static tree
-fld_simplified_type (tree t, class free_lang_data_d *fld)
+bool
+check_qualified_type (const_tree cand, const_tree base, int type_quals)
 {
-  if (!t)
-    return t;
-  if (POINTER_TYPE_P (t))
-    return fld_incomplete_type_of (t, fld);
-  /* FIXME: This triggers verification error, see PR88140.  */
-#if 0
-  if (TREE_CODE (t) == ARRAY_TYPE)
-    return fld_process_array_type (t, fld_simplified_type (TREE_TYPE (t), fld),
-                                  fld_simplified_types, fld);
-#endif
-  return t;
+  return (TYPE_QUALS (cand) == type_quals
+         && check_base_type (cand, base)
+         && check_lang_type (cand, base));
 }
 
-/* Reset the expression *EXPR_P, a size or position.
-
-   ??? We could reset all non-constant sizes or positions.  But it's cheap
-   enough to not do so and refrain from adding workarounds to dwarf2out.c.
-
-   We need to reset self-referential sizes or positions because they cannot
-   be gimplified and thus can contain a CALL_EXPR after the gimplification
-   is finished, which will run afoul of LTO streaming.  And they need to be
-   reset to something essentially dummy but not constant, so as to preserve
-   the properties of the object they are attached to.  */
+/* Returns true iff CAND is equivalent to BASE with ALIGN.  */
 
-static inline void
-free_lang_data_in_one_sizepos (tree *expr_p)
-{
-  tree expr = *expr_p;
-  if (CONTAINS_PLACEHOLDER_P (expr))
-    *expr_p = build0 (PLACEHOLDER_EXPR, TREE_TYPE (expr));
-}
-
-
-/* Reset all the fields in a binfo node BINFO.  We only keep
-   BINFO_VTABLE, which is used by gimple_fold_obj_type_ref.  */
-
-static void
-free_lang_data_in_binfo (tree binfo)
-{
-  unsigned i;
-  tree t;
-
-  gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
-
-  BINFO_VIRTUALS (binfo) = NULL_TREE;
-  BINFO_BASE_ACCESSES (binfo) = NULL;
-  BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
-  BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
-  BINFO_VPTR_FIELD (binfo) = NULL_TREE;
-  TREE_PUBLIC (binfo) = 0;
-
-  FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (binfo), i, t)
-    free_lang_data_in_binfo (t);
-}
-
-
-/* Reset all language specific information still present in TYPE.  */
-
-static void
-free_lang_data_in_type (tree type, class free_lang_data_d *fld)
-{
-  gcc_assert (TYPE_P (type));
-
-  /* Give the FE a chance to remove its own data first.  */
-  lang_hooks.free_lang_data (type);
-
-  TREE_LANG_FLAG_0 (type) = 0;
-  TREE_LANG_FLAG_1 (type) = 0;
-  TREE_LANG_FLAG_2 (type) = 0;
-  TREE_LANG_FLAG_3 (type) = 0;
-  TREE_LANG_FLAG_4 (type) = 0;
-  TREE_LANG_FLAG_5 (type) = 0;
-  TREE_LANG_FLAG_6 (type) = 0;
-
-  TYPE_NEEDS_CONSTRUCTING (type) = 0;
-
-  /* Purge non-marked variants from the variants chain, so that they
-     don't reappear in the IL after free_lang_data.  */
-  while (TYPE_NEXT_VARIANT (type)
-        && !fld->pset.contains (TYPE_NEXT_VARIANT (type)))
-    {
-      tree t = TYPE_NEXT_VARIANT (type);
-      TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
-      /* Turn the removed types into distinct types.  */
-      TYPE_MAIN_VARIANT (t) = t;
-      TYPE_NEXT_VARIANT (t) = NULL_TREE;
-    }
-
-  if (TREE_CODE (type) == FUNCTION_TYPE)
-    {
-      TREE_TYPE (type) = fld_simplified_type (TREE_TYPE (type), fld);
-      /* Remove the const and volatile qualifiers from arguments.  The
-        C++ front end removes them, but the C front end does not,
-        leading to false ODR violation errors when merging two
-        instances of the same function signature compiled by
-        different front ends.  */
-      for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
-       {
-          TREE_VALUE (p) = fld_simplified_type (TREE_VALUE (p), fld);
-         tree arg_type = TREE_VALUE (p);
-
-         if (TYPE_READONLY (arg_type) || TYPE_VOLATILE (arg_type))
-           {
-             int quals = TYPE_QUALS (arg_type)
-                         & ~TYPE_QUAL_CONST
-                         & ~TYPE_QUAL_VOLATILE;
-             TREE_VALUE (p) = build_qualified_type (arg_type, quals);
-             if (!fld->pset.add (TREE_VALUE (p)))
-               free_lang_data_in_type (TREE_VALUE (p), fld);
-           }
-         /* C++ FE uses TREE_PURPOSE to store initial values.  */
-         TREE_PURPOSE (p) = NULL;
-       }
-    }
-  else if (TREE_CODE (type) == METHOD_TYPE)
-    {
-      TREE_TYPE (type) = fld_simplified_type (TREE_TYPE (type), fld);
-      for (tree p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p))
-       {
-         /* C++ FE uses TREE_PURPOSE to store initial values.  */
-         TREE_VALUE (p) = fld_simplified_type (TREE_VALUE (p), fld);
-         TREE_PURPOSE (p) = NULL;
-       }
-    }
-  else if (RECORD_OR_UNION_TYPE_P (type))
-    {
-      /* Remove members that are not FIELD_DECLs from the field list
-        of an aggregate.  These occur in C++.  */
-      for (tree *prev = &TYPE_FIELDS (type), member; (member = *prev);)
-       if (TREE_CODE (member) == FIELD_DECL)
-         prev = &DECL_CHAIN (member);
-       else
-         *prev = DECL_CHAIN (member);
-
-      TYPE_VFIELD (type) = NULL_TREE;
-
-      if (TYPE_BINFO (type))
-       {
-         free_lang_data_in_binfo (TYPE_BINFO (type));
-         /* We need to preserve link to bases and virtual table for all
-            polymorphic types to make devirtualization machinery working.  */
-         if (!BINFO_VTABLE (TYPE_BINFO (type)))
-           TYPE_BINFO (type) = NULL;
-       }
-    }
-  else if (INTEGRAL_TYPE_P (type)
-          || SCALAR_FLOAT_TYPE_P (type)
-          || FIXED_POINT_TYPE_P (type))
-    {
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-       {
-         ENUM_IS_OPAQUE (type) = 0;
-         ENUM_IS_SCOPED (type) = 0;
-         /* Type values are used only for C++ ODR checking.  Drop them
-            for all type variants and non-ODR types.
-            For ODR types the data is freed in free_odr_warning_data.  */
-         if (!TYPE_VALUES (type))
-           ;
-         else if (TYPE_MAIN_VARIANT (type) != type
-                  || !type_with_linkage_p (type)
-                  || type_in_anonymous_namespace_p (type))
-           TYPE_VALUES (type) = NULL;
-         else
-           register_odr_enum (type);
-       }
-      free_lang_data_in_one_sizepos (&TYPE_MIN_VALUE (type));
-      free_lang_data_in_one_sizepos (&TYPE_MAX_VALUE (type));
-    }
-
-  TYPE_LANG_SLOT_1 (type) = NULL_TREE;
-
-  free_lang_data_in_one_sizepos (&TYPE_SIZE (type));
-  free_lang_data_in_one_sizepos (&TYPE_SIZE_UNIT (type));
-
-  if (TYPE_CONTEXT (type)
-      && TREE_CODE (TYPE_CONTEXT (type)) == BLOCK)
-    {
-      tree ctx = TYPE_CONTEXT (type);
-      do
-       {
-         ctx = BLOCK_SUPERCONTEXT (ctx);
-       }
-      while (ctx && TREE_CODE (ctx) == BLOCK);
-      TYPE_CONTEXT (type) = ctx;
-    }
-
-  TYPE_STUB_DECL (type) = NULL;
-  TYPE_NAME (type) = fld_simplified_type_name (type);
-}
-
-
-/* Return true if DECL may need an assembler name to be set.  */
-
-static inline bool
-need_assembler_name_p (tree decl)
-{
-  /* We use DECL_ASSEMBLER_NAME to hold mangled type names for One Definition
-     Rule merging.  This makes type_odr_p to return true on those types during
-     LTO and by comparing the mangled name, we can say what types are intended
-     to be equivalent across compilation unit.
-
-     We do not store names of type_in_anonymous_namespace_p.
-
-     Record, union and enumeration type have linkage that allows use
-     to check type_in_anonymous_namespace_p. We do not mangle compound types
-     that always can be compared structurally.
-
-     Similarly for builtin types, we compare properties of their main variant.
-     A special case are integer types where mangling do make differences
-     between char/signed char/unsigned char etc.  Storing name for these makes
-     e.g.  -fno-signed-char/-fsigned-char mismatches to be handled well.
-     See cp/mangle.c:write_builtin_type for details.  */
-
-  if (TREE_CODE (decl) == TYPE_DECL)
-    {
-      if (DECL_NAME (decl)
-         && decl == TYPE_NAME (TREE_TYPE (decl))
-         && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == TREE_TYPE (decl)
-         && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
-         && ((TREE_CODE (TREE_TYPE (decl)) != RECORD_TYPE
-              && TREE_CODE (TREE_TYPE (decl)) != UNION_TYPE)
-             || TYPE_CXX_ODR_P (TREE_TYPE (decl)))
-         && (type_with_linkage_p (TREE_TYPE (decl))
-             || TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
-         && !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
-       return !DECL_ASSEMBLER_NAME_SET_P (decl);
-      return false;
-    }
-  /* Only FUNCTION_DECLs and VAR_DECLs are considered.  */
-  if (!VAR_OR_FUNCTION_DECL_P (decl))
-    return false;
-
-  /* If DECL already has its assembler name set, it does not need a
-     new one.  */
-  if (!HAS_DECL_ASSEMBLER_NAME_P (decl)
-      || DECL_ASSEMBLER_NAME_SET_P (decl))
-    return false;
-
-  /* Abstract decls do not need an assembler name.  */
-  if (DECL_ABSTRACT_P (decl))
-    return false;
-
-  /* For VAR_DECLs, only static, public and external symbols need an
-     assembler name.  */
-  if (VAR_P (decl)
-      && !TREE_STATIC (decl)
-      && !TREE_PUBLIC (decl)
-      && !DECL_EXTERNAL (decl))
-    return false;
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      /* Do not set assembler name on builtins.  Allow RTL expansion to
-        decide whether to expand inline or via a regular call.  */
-      if (fndecl_built_in_p (decl)
-         && DECL_BUILT_IN_CLASS (decl) != BUILT_IN_FRONTEND)
-       return false;
-
-      /* Functions represented in the callgraph need an assembler name.  */
-      if (cgraph_node::get (decl) != NULL)
-       return true;
-
-      /* Unused and not public functions don't need an assembler name.  */
-      if (!TREE_USED (decl) && !TREE_PUBLIC (decl))
-       return false;
-    }
-
-  return true;
-}
-
-
-/* Reset all language specific information still present in symbol
-   DECL.  */
-
-static void
-free_lang_data_in_decl (tree decl, class free_lang_data_d *fld)
-{
-  gcc_assert (DECL_P (decl));
-
-  /* Give the FE a chance to remove its own data first.  */
-  lang_hooks.free_lang_data (decl);
-
-  TREE_LANG_FLAG_0 (decl) = 0;
-  TREE_LANG_FLAG_1 (decl) = 0;
-  TREE_LANG_FLAG_2 (decl) = 0;
-  TREE_LANG_FLAG_3 (decl) = 0;
-  TREE_LANG_FLAG_4 (decl) = 0;
-  TREE_LANG_FLAG_5 (decl) = 0;
-  TREE_LANG_FLAG_6 (decl) = 0;
-
-  free_lang_data_in_one_sizepos (&DECL_SIZE (decl));
-  free_lang_data_in_one_sizepos (&DECL_SIZE_UNIT (decl));
-  if (TREE_CODE (decl) == FIELD_DECL)
-    {
-      DECL_FCONTEXT (decl) = NULL;
-      free_lang_data_in_one_sizepos (&DECL_FIELD_OFFSET (decl));
-      if (TREE_CODE (DECL_CONTEXT (decl)) == QUAL_UNION_TYPE)
-       DECL_QUALIFIER (decl) = NULL_TREE;
-    }
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      struct cgraph_node *node;
-      /* Frontends do not set TREE_ADDRESSABLE on public variables even though
-        the address may be taken in other unit, so this flag has no practical
-        use for middle-end.
-
-        It would make more sense if frontends set TREE_ADDRESSABLE to 0 only
-        for public objects that indeed cannot be adressed, but it is not
-        the case.  Set the flag to true so we do not get merge failures for
-        i.e. virtual tables between units that take address of it and
-        units that don't.  */
-      if (TREE_PUBLIC (decl))
-       TREE_ADDRESSABLE (decl) = true;
-      TREE_TYPE (decl) = fld_simplified_type (TREE_TYPE (decl), fld);
-      if (!(node = cgraph_node::get (decl))
-         || (!node->definition && !node->clones))
-       {
-         if (node && !node->declare_variant_alt)
-           node->release_body ();
-         else
-           {
-             release_function_body (decl);
-             DECL_ARGUMENTS (decl) = NULL;
-             DECL_RESULT (decl) = NULL;
-             DECL_INITIAL (decl) = error_mark_node;
-           }
-       }
-      if (gimple_has_body_p (decl) || (node && node->thunk))
-       {
-         tree t;
-
-         /* If DECL has a gimple body, then the context for its
-            arguments must be DECL.  Otherwise, it doesn't really
-            matter, as we will not be emitting any code for DECL.  In
-            general, there may be other instances of DECL created by
-            the front end and since PARM_DECLs are generally shared,
-            their DECL_CONTEXT changes as the replicas of DECL are
-            created.  The only time where DECL_CONTEXT is important
-            is for the FUNCTION_DECLs that have a gimple body (since
-            the PARM_DECL will be used in the function's body).  */
-         for (t = DECL_ARGUMENTS (decl); t; t = TREE_CHAIN (t))
-           DECL_CONTEXT (t) = decl;
-         if (!DECL_FUNCTION_SPECIFIC_TARGET (decl))
-           DECL_FUNCTION_SPECIFIC_TARGET (decl)
-             = target_option_default_node;
-         if (!DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))
-           DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl)
-             = optimization_default_node;
-       }
-
-      /* DECL_SAVED_TREE holds the GENERIC representation for DECL.
-        At this point, it is not needed anymore.  */
-      DECL_SAVED_TREE (decl) = NULL_TREE;
-
-      /* Clear the abstract origin if it refers to a method.
-         Otherwise dwarf2out.c will ICE as we splice functions out of
-         TYPE_FIELDS and thus the origin will not be output
-         correctly.  */
-      if (DECL_ABSTRACT_ORIGIN (decl)
-         && DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))
-         && RECORD_OR_UNION_TYPE_P
-              (DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))))
-       DECL_ABSTRACT_ORIGIN (decl) = NULL_TREE;
-
-      DECL_VINDEX (decl) = NULL_TREE;
-    }
-  else if (VAR_P (decl))
-    {
-      /* See comment above why we set the flag for functions.  */
-      if (TREE_PUBLIC (decl))
-       TREE_ADDRESSABLE (decl) = true;
-      if ((DECL_EXTERNAL (decl)
-          && (!TREE_STATIC (decl) || !TREE_READONLY (decl)))
-         || (decl_function_context (decl) && !TREE_STATIC (decl)))
-       DECL_INITIAL (decl) = NULL_TREE;
-    }
-  else if (TREE_CODE (decl) == TYPE_DECL)
-    {
-      DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (decl) = 0;
-      TREE_PUBLIC (decl) = 0;
-      TREE_PRIVATE (decl) = 0;
-      DECL_ARTIFICIAL (decl) = 0;
-      TYPE_DECL_SUPPRESS_DEBUG (decl) = 0;
-      DECL_INITIAL (decl) = NULL_TREE;
-      DECL_ORIGINAL_TYPE (decl) = NULL_TREE;
-      DECL_MODE (decl) = VOIDmode;
-      SET_DECL_ALIGN (decl, 0);
-      /* TREE_TYPE is cleared at WPA time in free_odr_warning_data.  */
-    }
-  else if (TREE_CODE (decl) == FIELD_DECL)
-    {
-      TREE_TYPE (decl) = fld_simplified_type (TREE_TYPE (decl), fld);
-      DECL_INITIAL (decl) = NULL_TREE;
-    }
-  else if (TREE_CODE (decl) == TRANSLATION_UNIT_DECL
-           && DECL_INITIAL (decl)
-           && TREE_CODE (DECL_INITIAL (decl)) == BLOCK)
-    {
-      /* Strip builtins from the translation-unit BLOCK.  We still have targets
-        without builtin_decl_explicit support and also builtins are shared
-        nodes and thus we can't use TREE_CHAIN in multiple lists.  */
-      tree *nextp = &BLOCK_VARS (DECL_INITIAL (decl));
-      while (*nextp)
-       {
-         tree var = *nextp;
-         if (TREE_CODE (var) == FUNCTION_DECL
-             && fndecl_built_in_p (var))
-           *nextp = TREE_CHAIN (var);
-         else
-           nextp = &TREE_CHAIN (var);
-        }
-    }
-  /* We need to keep field decls associated with their trees. Otherwise tree
-     merging may merge some fileds and keep others disjoint wich in turn will
-     not do well with TREE_CHAIN pointers linking them.
-
-     Also do not drop containing types for virtual methods and tables because
-     these are needed by devirtualization.
-     C++ destructors are special because C++ frontends sometimes produces
-     virtual destructor as an alias of non-virtual destructor.  In
-     devirutalization code we always walk through aliases and we need
-     context to be preserved too.  See PR89335  */
-  if (TREE_CODE (decl) != FIELD_DECL
-      && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
-          || (!DECL_VIRTUAL_P (decl)
-             && (TREE_CODE (decl) != FUNCTION_DECL
-                 || !DECL_CXX_DESTRUCTOR_P (decl)))))
-    DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl));
-}
-
-
-/* Operand callback helper for free_lang_data_in_node.  *TP is the
-   subtree operand being considered.  */
-
-static tree
-find_decls_types_r (tree *tp, int *ws, void *data)
-{
-  tree t = *tp;
-  class free_lang_data_d *fld = (class free_lang_data_d *) data;
-
-  if (TREE_CODE (t) == TREE_LIST)
-    return NULL_TREE;
-
-  /* Language specific nodes will be removed, so there is no need
-     to gather anything under them.  */
-  if (is_lang_specific (t))
-    {
-      *ws = 0;
-      return NULL_TREE;
-    }
-
-  if (DECL_P (t))
-    {
-      /* Note that walk_tree does not traverse every possible field in
-        decls, so we have to do our own traversals here.  */
-      add_tree_to_fld_list (t, fld);
-
-      fld_worklist_push (DECL_NAME (t), fld);
-      fld_worklist_push (DECL_CONTEXT (t), fld);
-      fld_worklist_push (DECL_SIZE (t), fld);
-      fld_worklist_push (DECL_SIZE_UNIT (t), fld);
-
-      /* We are going to remove everything under DECL_INITIAL for
-        TYPE_DECLs.  No point walking them.  */
-      if (TREE_CODE (t) != TYPE_DECL)
-       fld_worklist_push (DECL_INITIAL (t), fld);
-
-      fld_worklist_push (DECL_ATTRIBUTES (t), fld);
-      fld_worklist_push (DECL_ABSTRACT_ORIGIN (t), fld);
-
-      if (TREE_CODE (t) == FUNCTION_DECL)
-       {
-         fld_worklist_push (DECL_ARGUMENTS (t), fld);
-         fld_worklist_push (DECL_RESULT (t), fld);
-       }
-      else if (TREE_CODE (t) == FIELD_DECL)
-       {
-         fld_worklist_push (DECL_FIELD_OFFSET (t), fld);
-         fld_worklist_push (DECL_BIT_FIELD_TYPE (t), fld);
-         fld_worklist_push (DECL_FIELD_BIT_OFFSET (t), fld);
-         fld_worklist_push (DECL_FCONTEXT (t), fld);
-       }
-
-      if ((VAR_P (t) || TREE_CODE (t) == PARM_DECL)
-         && DECL_HAS_VALUE_EXPR_P (t))
-       fld_worklist_push (DECL_VALUE_EXPR (t), fld);
-
-      if (TREE_CODE (t) != FIELD_DECL
-         && TREE_CODE (t) != TYPE_DECL)
-       fld_worklist_push (TREE_CHAIN (t), fld);
-      *ws = 0;
-    }
-  else if (TYPE_P (t))
-    {
-      /* Note that walk_tree does not traverse every possible field in
-        types, so we have to do our own traversals here.  */
-      add_tree_to_fld_list (t, fld);
-
-      if (!RECORD_OR_UNION_TYPE_P (t))
-       fld_worklist_push (TYPE_CACHED_VALUES (t), fld);
-      fld_worklist_push (TYPE_SIZE (t), fld);
-      fld_worklist_push (TYPE_SIZE_UNIT (t), fld);
-      fld_worklist_push (TYPE_ATTRIBUTES (t), fld);
-      fld_worklist_push (TYPE_POINTER_TO (t), fld);
-      fld_worklist_push (TYPE_REFERENCE_TO (t), fld);
-      fld_worklist_push (TYPE_NAME (t), fld);
-      /* While we do not stream TYPE_POINTER_TO and TYPE_REFERENCE_TO
-        lists, we may look types up in these lists and use them while
-        optimizing the function body.  Thus we need to free lang data
-        in them.  */
-      if (TREE_CODE (t) == POINTER_TYPE)
-        fld_worklist_push (TYPE_NEXT_PTR_TO (t), fld);
-      if (TREE_CODE (t) == REFERENCE_TYPE)
-        fld_worklist_push (TYPE_NEXT_REF_TO (t), fld);
-      if (!POINTER_TYPE_P (t))
-       fld_worklist_push (TYPE_MIN_VALUE_RAW (t), fld);
-      /* TYPE_MAX_VALUE_RAW is TYPE_BINFO for record types.  */
-      if (!RECORD_OR_UNION_TYPE_P (t))
-       fld_worklist_push (TYPE_MAX_VALUE_RAW (t), fld);
-      fld_worklist_push (TYPE_MAIN_VARIANT (t), fld);
-      /* Do not walk TYPE_NEXT_VARIANT.  We do not stream it and thus
-         do not and want not to reach unused variants this way.  */
-      if (TYPE_CONTEXT (t))
-       {
-         tree ctx = TYPE_CONTEXT (t);
-         /* We adjust BLOCK TYPE_CONTEXTs to the innermost non-BLOCK one.
-            So push that instead.  */
-         while (ctx && TREE_CODE (ctx) == BLOCK)
-           ctx = BLOCK_SUPERCONTEXT (ctx);
-         fld_worklist_push (ctx, fld);
-       }
-      fld_worklist_push (TYPE_CANONICAL (t), fld);
-
-      if (RECORD_OR_UNION_TYPE_P (t) && TYPE_BINFO (t))
-       {
-         unsigned i;
-         tree tem;
-         FOR_EACH_VEC_ELT (*BINFO_BASE_BINFOS (TYPE_BINFO (t)), i, tem)
-           fld_worklist_push (TREE_TYPE (tem), fld);
-         fld_worklist_push (BINFO_TYPE (TYPE_BINFO (t)), fld);
-         fld_worklist_push (BINFO_VTABLE (TYPE_BINFO (t)), fld);
-       }
-      if (RECORD_OR_UNION_TYPE_P (t))
-       {
-         tree tem;
-         /* Push all TYPE_FIELDS - there can be interleaving interesting
-            and non-interesting things.  */
-         tem = TYPE_FIELDS (t);
-         while (tem)
-           {
-             if (TREE_CODE (tem) == FIELD_DECL)
-               fld_worklist_push (tem, fld);
-             tem = TREE_CHAIN (tem);
-           }
-       }
-      if (FUNC_OR_METHOD_TYPE_P (t))
-       fld_worklist_push (TYPE_METHOD_BASETYPE (t), fld);
-
-      fld_worklist_push (TYPE_STUB_DECL (t), fld);
-      *ws = 0;
-    }
-  else if (TREE_CODE (t) == BLOCK)
-    {
-      for (tree *tem = &BLOCK_VARS (t); *tem; )
-       {
-         if (TREE_CODE (*tem) != LABEL_DECL
-             && (TREE_CODE (*tem) != VAR_DECL
-                 || !auto_var_in_fn_p (*tem, DECL_CONTEXT (*tem))))
-           {
-             gcc_assert (TREE_CODE (*tem) != RESULT_DECL
-                         && TREE_CODE (*tem) != PARM_DECL);
-             *tem = TREE_CHAIN (*tem);
-           }
-         else 
-           {
-             fld_worklist_push (*tem, fld);
-             tem = &TREE_CHAIN (*tem);
-           }
-       }
-      for (tree tem = BLOCK_SUBBLOCKS (t); tem; tem = BLOCK_CHAIN (tem))
-       fld_worklist_push (tem, fld);
-      fld_worklist_push (BLOCK_ABSTRACT_ORIGIN (t), fld);
-    }
-
-  if (TREE_CODE (t) != IDENTIFIER_NODE
-      && CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPED))
-    fld_worklist_push (TREE_TYPE (t), fld);
-
-  return NULL_TREE;
-}
-
-
-/* Find decls and types in T.  */
-
-static void
-find_decls_types (tree t, class free_lang_data_d *fld)
-{
-  while (1)
-    {
-      if (!fld->pset.contains (t))
-       walk_tree (&t, find_decls_types_r, fld, &fld->pset);
-      if (fld->worklist.is_empty ())
-       break;
-      t = fld->worklist.pop ();
-    }
-}
-
-/* Translate all the types in LIST with the corresponding runtime
-   types.  */
-
-static tree
-get_eh_types_for_runtime (tree list)
-{
-  tree head, prev;
-
-  if (list == NULL_TREE)
-    return NULL_TREE;
-
-  head = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list)));
-  prev = head;
-  list = TREE_CHAIN (list);
-  while (list)
-    {
-      tree n = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list)));
-      TREE_CHAIN (prev) = n;
-      prev = TREE_CHAIN (prev);
-      list = TREE_CHAIN (list);
-    }
-
-  return head;
-}
-
-
-/* Find decls and types referenced in EH region R and store them in
-   FLD->DECLS and FLD->TYPES.  */
-
-static void
-find_decls_types_in_eh_region (eh_region r, class free_lang_data_d *fld)
-{
-  switch (r->type)
-    {
-    case ERT_CLEANUP:
-      break;
-
-    case ERT_TRY:
-      {
-       eh_catch c;
-
-       /* The types referenced in each catch must first be changed to the
-          EH types used at runtime.  This removes references to FE types
-          in the region.  */
-       for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
-         {
-           c->type_list = get_eh_types_for_runtime (c->type_list);
-           walk_tree (&c->type_list, find_decls_types_r, fld, &fld->pset);
-         }
-      }
-      break;
-
-    case ERT_ALLOWED_EXCEPTIONS:
-      r->u.allowed.type_list
-       = get_eh_types_for_runtime (r->u.allowed.type_list);
-      walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, &fld->pset);
-      break;
-
-    case ERT_MUST_NOT_THROW:
-      walk_tree (&r->u.must_not_throw.failure_decl,
-                find_decls_types_r, fld, &fld->pset);
-      break;
-    }
-}
-
-
-/* Find decls and types referenced in cgraph node N and store them in
-   FLD->DECLS and FLD->TYPES.  Unlike pass_referenced_vars, this will
-   look for *every* kind of DECL and TYPE node reachable from N,
-   including those embedded inside types and decls (i.e,, TYPE_DECLs,
-   NAMESPACE_DECLs, etc).  */
-
-static void
-find_decls_types_in_node (struct cgraph_node *n, class free_lang_data_d *fld)
-{
-  basic_block bb;
-  struct function *fn;
-  unsigned ix;
-  tree t;
-
-  find_decls_types (n->decl, fld);
-
-  if (!gimple_has_body_p (n->decl))
-    return;
-
-  gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
-
-  fn = DECL_STRUCT_FUNCTION (n->decl);
-
-  /* Traverse locals. */
-  FOR_EACH_LOCAL_DECL (fn, ix, t)
-    find_decls_types (t, fld);
-
-  /* Traverse EH regions in FN.  */
-  {
-    eh_region r;
-    FOR_ALL_EH_REGION_FN (r, fn)
-      find_decls_types_in_eh_region (r, fld);
-  }
-
-  /* Traverse every statement in FN.  */
-  FOR_EACH_BB_FN (bb, fn)
-    {
-      gphi_iterator psi;
-      gimple_stmt_iterator si;
-      unsigned i;
-
-      for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
-       {
-         gphi *phi = psi.phi ();
-
-         for (i = 0; i < gimple_phi_num_args (phi); i++)
-           {
-             tree *arg_p = gimple_phi_arg_def_ptr (phi, i);
-             find_decls_types (*arg_p, fld);
-           }
-       }
-
-      for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
-       {
-         gimple *stmt = gsi_stmt (si);
-
-         if (is_gimple_call (stmt))
-           find_decls_types (gimple_call_fntype (stmt), fld);
-
-         for (i = 0; i < gimple_num_ops (stmt); i++)
-           {
-             tree arg = gimple_op (stmt, i);
-             find_decls_types (arg, fld);
-             /* find_decls_types doesn't walk TREE_PURPOSE of TREE_LISTs,
-                which we need for asm stmts.  */
-             if (arg
-                 && TREE_CODE (arg) == TREE_LIST
-                 && TREE_PURPOSE (arg)
-                 && gimple_code (stmt) == GIMPLE_ASM)
-               find_decls_types (TREE_PURPOSE (arg), fld);
-           }
-       }
-    }
-}
-
-
-/* Find decls and types referenced in varpool node N and store them in
-   FLD->DECLS and FLD->TYPES.  Unlike pass_referenced_vars, this will
-   look for *every* kind of DECL and TYPE node reachable from N,
-   including those embedded inside types and decls (i.e,, TYPE_DECLs,
-   NAMESPACE_DECLs, etc).  */
-
-static void
-find_decls_types_in_var (varpool_node *v, class free_lang_data_d *fld)
-{
-  find_decls_types (v->decl, fld);
-}
-
-/* If T needs an assembler name, have one created for it.  */
-
-void
-assign_assembler_name_if_needed (tree t)
-{
-  if (need_assembler_name_p (t))
-    {
-      /* When setting DECL_ASSEMBLER_NAME, the C++ mangler may emit
-        diagnostics that use input_location to show locus
-        information.  The problem here is that, at this point,
-        input_location is generally anchored to the end of the file
-        (since the parser is long gone), so we don't have a good
-        position to pin it to.
-
-        To alleviate this problem, this uses the location of T's
-        declaration.  Examples of this are
-        testsuite/g++.dg/template/cond2.C and
-        testsuite/g++.dg/template/pr35240.C.  */
-      location_t saved_location = input_location;
-      input_location = DECL_SOURCE_LOCATION (t);
-
-      decl_assembler_name (t);
-
-      input_location = saved_location;
-    }
-}
-
-
-/* Free language specific information for every operand and expression
-   in every node of the call graph.  This process operates in three stages:
-
-   1- Every callgraph node and varpool node is traversed looking for
-      decls and types embedded in them.  This is a more exhaustive
-      search than that done by find_referenced_vars, because it will
-      also collect individual fields, decls embedded in types, etc.
-
-   2- All the decls found are sent to free_lang_data_in_decl.
-
-   3- All the types found are sent to free_lang_data_in_type.
-
-   The ordering between decls and types is important because
-   free_lang_data_in_decl sets assembler names, which includes
-   mangling.  So types cannot be freed up until assembler names have
-   been set up.  */
-
-static void
-free_lang_data_in_cgraph (class free_lang_data_d *fld)
-{
-  struct cgraph_node *n;
-  varpool_node *v;
-  tree t;
-  unsigned i;
-  alias_pair *p;
-
-  /* Find decls and types in the body of every function in the callgraph.  */
-  FOR_EACH_FUNCTION (n)
-    find_decls_types_in_node (n, fld);
-
-  FOR_EACH_VEC_SAFE_ELT (alias_pairs, i, p)
-    find_decls_types (p->decl, fld);
-
-  /* Find decls and types in every varpool symbol.  */
-  FOR_EACH_VARIABLE (v)
-    find_decls_types_in_var (v, fld);
-
-  /* Set the assembler name on every decl found.  We need to do this
-     now because free_lang_data_in_decl will invalidate data needed
-     for mangling.  This breaks mangling on interdependent decls.  */
-  FOR_EACH_VEC_ELT (fld->decls, i, t)
-    assign_assembler_name_if_needed (t);
-
-  /* Traverse every decl found freeing its language data.  */
-  FOR_EACH_VEC_ELT (fld->decls, i, t)
-    free_lang_data_in_decl (t, fld);
-
-  /* Traverse every type found freeing its language data.  */
-  FOR_EACH_VEC_ELT (fld->types, i, t)
-    free_lang_data_in_type (t, fld);
-}
-
-
-/* Free resources that are used by FE but are not needed once they are done. */
-
-static unsigned
-free_lang_data (void)
-{
-  unsigned i;
-  class free_lang_data_d fld;
-
-  /* If we are the LTO frontend we have freed lang-specific data already.  */
-  if (in_lto_p
-      || (!flag_generate_lto && !flag_generate_offload))
-    {
-      /* Rebuild type inheritance graph even when not doing LTO to get
-        consistent profile data.  */
-      rebuild_type_inheritance_graph ();
-      return 0;
-    }
-
-  fld_incomplete_types = new hash_map<tree, tree>;
-  fld_simplified_types = new hash_map<tree, tree>;
-
-  /* Provide a dummy TRANSLATION_UNIT_DECL if the FE failed to provide one.  */
-  if (vec_safe_is_empty (all_translation_units))
-    build_translation_unit_decl (NULL_TREE);
-
-  /* Allocate and assign alias sets to the standard integer types
-     while the slots are still in the way the frontends generated them.  */
-  for (i = 0; i < itk_none; ++i)
-    if (integer_types[i])
-      TYPE_ALIAS_SET (integer_types[i]) = get_alias_set (integer_types[i]);
-
-  /* Traverse the IL resetting language specific information for
-     operands, expressions, etc.  */
-  free_lang_data_in_cgraph (&fld);
-
-  /* Create gimple variants for common types.  */
-  for (unsigned i = 0;
-       i < sizeof (builtin_structptr_types) / sizeof (builtin_structptr_type);
-       ++i)
-    builtin_structptr_types[i].node = builtin_structptr_types[i].base;
-
-  /* Reset some langhooks.  Do not reset types_compatible_p, it may
-     still be used indirectly via the get_alias_set langhook.  */
-  lang_hooks.dwarf_name = lhd_dwarf_name;
-  lang_hooks.decl_printable_name = gimple_decl_printable_name;
-  lang_hooks.gimplify_expr = lhd_gimplify_expr;
-  lang_hooks.overwrite_decl_assembler_name = lhd_overwrite_decl_assembler_name;
-  lang_hooks.print_xnode = lhd_print_tree_nothing;
-  lang_hooks.print_decl = lhd_print_tree_nothing;
-  lang_hooks.print_type = lhd_print_tree_nothing;
-  lang_hooks.print_identifier = lhd_print_tree_nothing;
-
-  lang_hooks.tree_inlining.var_mod_type_p = hook_bool_tree_tree_false;
-
-  if (flag_checking)
-    {
-      int i;
-      tree t;
-
-      FOR_EACH_VEC_ELT (fld.types, i, t)
-       verify_type (t);
-    }
-
-  /* We do not want the default decl_assembler_name implementation,
-     rather if we have fixed everything we want a wrapper around it
-     asserting that all non-local symbols already got their assembler
-     name and only produce assembler names for local symbols.  Or rather
-     make sure we never call decl_assembler_name on local symbols and
-     devise a separate, middle-end private scheme for it.  */
-
-  /* Reset diagnostic machinery.  */
-  tree_diagnostics_defaults (global_dc);
-
-  rebuild_type_inheritance_graph ();
-
-  delete fld_incomplete_types;
-  delete fld_simplified_types;
-
-  return 0;
-}
-
-
-namespace {
-
-const pass_data pass_data_ipa_free_lang_data =
-{
-  SIMPLE_IPA_PASS, /* type */
-  "*free_lang_data", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_IPA_FREE_LANG_DATA, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
-
-class pass_ipa_free_lang_data : public simple_ipa_opt_pass
-{
-public:
-  pass_ipa_free_lang_data (gcc::context *ctxt)
-    : simple_ipa_opt_pass (pass_data_ipa_free_lang_data, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  virtual unsigned int execute (function *) { return free_lang_data (); }
-
-}; // class pass_ipa_free_lang_data
-
-} // anon namespace
-
-simple_ipa_opt_pass *
-make_pass_ipa_free_lang_data (gcc::context *ctxt)
-{
-  return new pass_ipa_free_lang_data (ctxt);
-}
-\f
-/* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
-   of the various TYPE_QUAL values.  */
-
-static void
-set_type_quals (tree type, int type_quals)
-{
-  TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
-  TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
-  TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
-  TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0;
-  TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
-}
-
-/* Returns true iff CAND and BASE have equivalent language-specific
-   qualifiers.  */
-
-bool
-check_lang_type (const_tree cand, const_tree base)
-{
-  if (lang_hooks.types.type_hash_eq == NULL)
-    return true;
-  /* type_hash_eq currently only applies to these types.  */
-  if (TREE_CODE (cand) != FUNCTION_TYPE
-      && TREE_CODE (cand) != METHOD_TYPE)
-    return true;
-  return lang_hooks.types.type_hash_eq (cand, base);
-}
-
-/* This function checks to see if TYPE matches the size one of the built-in 
-   atomic types, and returns that core atomic type.  */
-
-static tree
-find_atomic_core_type (const_tree type)
-{
-  tree base_atomic_type;
-
-  /* Only handle complete types.  */
-  if (!tree_fits_uhwi_p (TYPE_SIZE (type)))
-    return NULL_TREE;
-
-  switch (tree_to_uhwi (TYPE_SIZE (type)))
-    {
-    case 8:
-      base_atomic_type = atomicQI_type_node;
-      break;
-
-    case 16:
-      base_atomic_type = atomicHI_type_node;
-      break;
-
-    case 32:
-      base_atomic_type = atomicSI_type_node;
-      break;
-
-    case 64:
-      base_atomic_type = atomicDI_type_node;
-      break;
-
-    case 128:
-      base_atomic_type = atomicTI_type_node;
-      break;
-
-    default:
-      base_atomic_type = NULL_TREE;
-    }
-
-  return base_atomic_type;
-}
-
-/* Returns true iff unqualified CAND and BASE are equivalent.  */
-
-bool
-check_base_type (const_tree cand, const_tree base)
-{
-  if (TYPE_NAME (cand) != TYPE_NAME (base)
-      /* Apparently this is needed for Objective-C.  */
-      || TYPE_CONTEXT (cand) != TYPE_CONTEXT (base)
-      || !attribute_list_equal (TYPE_ATTRIBUTES (cand),
-                               TYPE_ATTRIBUTES (base)))
-    return false;
-  /* Check alignment.  */
-  if (TYPE_ALIGN (cand) == TYPE_ALIGN (base)
-      && TYPE_USER_ALIGN (cand) == TYPE_USER_ALIGN (base))
-    return true;
-  /* Atomic types increase minimal alignment.  We must to do so as well
-     or we get duplicated canonical types. See PR88686.  */
-  if ((TYPE_QUALS (cand) & TYPE_QUAL_ATOMIC))
-    {
-      /* See if this object can map to a basic atomic type.  */
-      tree atomic_type = find_atomic_core_type (cand);
-      if (atomic_type && TYPE_ALIGN (atomic_type) == TYPE_ALIGN (cand))
-       return true;
-    }
-  return false;
-}
-
-/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS.  */
-
-bool
-check_qualified_type (const_tree cand, const_tree base, int type_quals)
-{
-  return (TYPE_QUALS (cand) == type_quals
-         && check_base_type (cand, base)
-         && check_lang_type (cand, base));
-}
-
-/* Returns true iff CAND is equivalent to BASE with ALIGN.  */
-
-static bool
-check_aligned_type (const_tree cand, const_tree base, unsigned int align)
+static bool
+check_aligned_type (const_tree cand, const_tree base, unsigned int align)
 {
   return (TYPE_QUALS (cand) == TYPE_QUALS (base)
          && TYPE_NAME (cand) == TYPE_NAME (base)
@@ -8263,7 +7119,7 @@ subrange_type_for_debug_p (const_tree type, tree *lowval, tree *highval)
    If SHARED is true, reuse such a type that has already been constructed.
    If SET_CANONICAL is true, compute TYPE_CANONICAL from the element type.  */
 
-static tree
+tree
 build_array_type_1 (tree elt_type, tree index_type, bool typeless_storage,
                    bool shared, bool set_canonical)
 {
index f00ea2ef0af86fc292b4417b59b9483bd0b4dc6d..5a609b98b4c650e08c935cec1e01dac95354f210 100644 (file)
@@ -4528,6 +4528,7 @@ extern tree build_vector_type (tree, poly_int64);
 extern tree build_truth_vector_type_for_mode (poly_uint64, machine_mode);
 extern tree build_opaque_vector_type (tree, poly_int64);
 extern tree build_index_type (tree);
+extern tree build_array_type_1 (tree, tree, bool, bool, bool);
 extern tree build_array_type (tree, tree, bool = false);
 extern tree build_nonshared_array_type (tree, tree);
 extern tree build_array_type_nelts (tree, poly_uint64);