public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-245] Move pass free_lang_data to its own file.
@ 2021-04-29  1:06 Martin Sebor
  0 siblings, 0 replies; only message in thread
From: Martin Sebor @ 2021-04-29  1:06 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:2de7c792569d7a227426aaeb124686a856614da7

commit r12-245-g2de7c792569d7a227426aaeb124686a856614da7
Author: Martin Sebor <msebor@redhat.com>
Date:   Wed Apr 28 19:01:40 2021 -0600

    Move pass free_lang_data to its own file.
    
    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.

Diff:
---
 gcc/Makefile.in           |    1 +
 gcc/ipa-free-lang-data.cc | 1188 +++++++++++++++++++++++++++++++++++
 gcc/tree.c                | 1512 ++++++---------------------------------------
 gcc/tree.h                |    1 +
 4 files changed, 1374 insertions(+), 1328 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8a5fb3fd99c..81c0d608b73 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
index 00000000000..0f2d43b25f1
--- /dev/null
+++ b/gcc/ipa-free-lang-data.cc
@@ -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);
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index 6129d911ee6..c5506a005bb 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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)
 {
diff --git a/gcc/tree.h b/gcc/tree.h
index f00ea2ef0af..5a609b98b4c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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);


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-04-29  1:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-29  1:06 [gcc r12-245] Move pass free_lang_data to its own file Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).