public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:4bae115bfd2c10fc975547b0d4ef9e9a98d51fa4

commit 4bae115bfd2c10fc975547b0d4ef9e9a98d51fa4
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Mon Jun 27 16:05:49 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    This changeset ports cp_global_trees structure which is used throughout the
    cp constexpr.cc code. I am not sure what it's purpose is but it seems it is used
    to add and manipulate tree information during the c++ compilation process.
    It is possible this is not needed in the Rust code and may be taken out later.
    Also, the initialization function isn't being called from anywhere yet, so
    we will need to find a suitable point for it.
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc |  93 ++++++++++++++
 gcc/rust/backend/rust-tree.h  | 280 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 373 insertions(+)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 3d71e19fe82..38c762b76d7 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -955,4 +955,97 @@ rs_type_quals (const_tree type)
   return quals;
 }
 
+// forked from gcc/cp/decl.cc cp_global_trees
+
+/* The following symbols are subsumed in the cp_global_trees array, and
+   listed here individually for documentation purposes.
+
+   C++ extensions
+	tree wchar_decl_node;
+
+	tree vtable_entry_type;
+	tree delta_type_node;
+	tree __t_desc_type_node;
+
+	tree class_type_node;
+	tree unknown_type_node;
+
+   Array type `vtable_entry_type[]'
+
+	tree vtbl_type_node;
+	tree vtbl_ptr_type_node;
+
+   Namespaces,
+
+	tree std_node;
+	tree abi_node;
+
+   A FUNCTION_DECL which can call `abort'.  Not necessarily the
+   one that the user will declare, but sufficient to be called
+   by routines that want to abort the program.
+
+	tree abort_fndecl;
+
+   Used by RTTI
+	tree type_info_type_node, tinfo_decl_id, tinfo_decl_type;
+	tree tinfo_var_id;  */
+
+tree cp_global_trees[CPTI_MAX];
+
+// forked from gcc/cp/module.cc fixed_trees
+
+static GTY (()) vec<tree, va_gc> *fixed_trees;
+
+// forked from gcc/cp/module.cc maybe_add_global
+
+/* VAL is a global tree, add it to the global vec if it is
+   interesting.  Add some of its targets, if they too are
+   interesting.  We do not add identifiers, as they can be re-found
+   via the identifier hash table.  There is a cost to the number of
+   global trees.  */
+
+static int
+maybe_add_global (tree val, unsigned &crc)
+{
+  int v = 0;
+
+  if (val && !(TREE_CODE (val) == IDENTIFIER_NODE || TREE_VISITED (val)))
+    {
+      TREE_VISITED (val) = true;
+      crc = crc32_unsigned (crc, fixed_trees->length ());
+      vec_safe_push (fixed_trees, val);
+      v++;
+
+      if (CODE_CONTAINS_STRUCT (TREE_CODE (val), TS_TYPED))
+	v += maybe_add_global (TREE_TYPE (val), crc);
+      if (CODE_CONTAINS_STRUCT (TREE_CODE (val), TS_TYPE_COMMON))
+	v += maybe_add_global (TYPE_NAME (val), crc);
+    }
+
+  return v;
+}
+
+// forked from gcc/cp/module.cc global_tree_arys
+
+/* Global trees.  */
+static const std::pair<tree *, unsigned> global_tree_arys[] = {
+  std::pair<tree *, unsigned> (cp_global_trees, CPTI_MODULE_HWM),
+};
+
+// forked from gcc/cp/module.cc init_modules
+
+void
+init_modules ()
+{
+  unsigned crc = 0;
+  vec_alloc (fixed_trees, 200);
+
+  const tree *ptr = global_tree_arys[0].first;
+  unsigned limit = global_tree_arys[0].second;
+  for (unsigned ix = 0; ix != limit; ix++, ptr++)
+    {
+      maybe_add_global (*ptr, crc);
+    }
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index a667cbfc8ad..f65d3ea2b7e 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -156,6 +156,283 @@
 #define VAR_OR_FUNCTION_DECL_CHECK(NODE)                                       \
   TREE_CHECK2 (NODE, VAR_DECL, FUNCTION_DECL)
 
+// forked from gcc/cp/cp-tree.h cp_tree_index
+
+enum cp_tree_index
+{
+  CPTI_WCHAR_DECL,
+  CPTI_VTABLE_ENTRY_TYPE,
+  CPTI_DELTA_TYPE,
+  CPTI_VTABLE_INDEX_TYPE,
+  CPTI_CLEANUP_TYPE,
+  CPTI_VTT_PARM_TYPE,
+
+  CPTI_CLASS_TYPE,
+  CPTI_UNKNOWN_TYPE,
+  CPTI_INIT_LIST_TYPE,
+  CPTI_EXPLICIT_VOID_LIST,
+  CPTI_VTBL_TYPE,
+  CPTI_VTBL_PTR_TYPE,
+  CPTI_GLOBAL,
+  CPTI_ABORT_FNDECL,
+  CPTI_AGGR_TAG,
+  CPTI_CONV_OP_MARKER,
+
+  CPTI_CTOR_IDENTIFIER,
+  CPTI_COMPLETE_CTOR_IDENTIFIER,
+  CPTI_BASE_CTOR_IDENTIFIER,
+  CPTI_DTOR_IDENTIFIER,
+  CPTI_COMPLETE_DTOR_IDENTIFIER,
+  CPTI_BASE_DTOR_IDENTIFIER,
+  CPTI_DELETING_DTOR_IDENTIFIER,
+  CPTI_CONV_OP_IDENTIFIER,
+  CPTI_DELTA_IDENTIFIER,
+  CPTI_IN_CHARGE_IDENTIFIER,
+  CPTI_VTT_PARM_IDENTIFIER,
+  CPTI_AS_BASE_IDENTIFIER,
+  CPTI_THIS_IDENTIFIER,
+  CPTI_PFN_IDENTIFIER,
+  CPTI_VPTR_IDENTIFIER,
+  CPTI_GLOBAL_IDENTIFIER,
+  CPTI_ANON_IDENTIFIER,
+  CPTI_AUTO_IDENTIFIER,
+  CPTI_DECLTYPE_AUTO_IDENTIFIER,
+  CPTI_INIT_LIST_IDENTIFIER,
+  CPTI_FOR_RANGE__IDENTIFIER,
+  CPTI_FOR_BEGIN__IDENTIFIER,
+  CPTI_FOR_END__IDENTIFIER,
+  CPTI_FOR_RANGE_IDENTIFIER,
+  CPTI_FOR_BEGIN_IDENTIFIER,
+  CPTI_FOR_END_IDENTIFIER,
+  CPTI_ABI_TAG_IDENTIFIER,
+  CPTI_ALIGNED_IDENTIFIER,
+  CPTI_BEGIN_IDENTIFIER,
+  CPTI_END_IDENTIFIER,
+  CPTI_GET_IDENTIFIER,
+  CPTI_GNU_IDENTIFIER,
+  CPTI_TUPLE_ELEMENT_IDENTIFIER,
+  CPTI_TUPLE_SIZE_IDENTIFIER,
+  CPTI_TYPE_IDENTIFIER,
+  CPTI_VALUE_IDENTIFIER,
+  CPTI_FUN_IDENTIFIER,
+  CPTI_CLOSURE_IDENTIFIER,
+  CPTI_HEAP_UNINIT_IDENTIFIER,
+  CPTI_HEAP_IDENTIFIER,
+  CPTI_HEAP_DELETED_IDENTIFIER,
+  CPTI_HEAP_VEC_UNINIT_IDENTIFIER,
+  CPTI_HEAP_VEC_IDENTIFIER,
+  CPTI_OMP_IDENTIFIER,
+
+  CPTI_LANG_NAME_C,
+  CPTI_LANG_NAME_CPLUSPLUS,
+
+  CPTI_EMPTY_EXCEPT_SPEC,
+  CPTI_NOEXCEPT_TRUE_SPEC,
+  CPTI_NOEXCEPT_FALSE_SPEC,
+  CPTI_NOEXCEPT_DEFERRED_SPEC,
+
+  CPTI_NULLPTR,
+  CPTI_NULLPTR_TYPE,
+
+  CPTI_ANY_TARG,
+
+  CPTI_MODULE_HWM,
+  /* Nodes after here change during compilation, or should not be in
+     the module's global tree table.  Such nodes must be locatable
+     via name lookup or type-construction, as those are the only
+     cross-TU matching capabilities remaining.  */
+
+  /* We must find these via the global namespace.  */
+  CPTI_STD,
+  CPTI_ABI,
+
+  /* These are created at init time, but the library/headers provide
+     definitions.  */
+  CPTI_ALIGN_TYPE,
+  CPTI_TERMINATE_FN,
+  CPTI_CALL_UNEXPECTED_FN,
+
+  /* These are lazily inited.  */
+  CPTI_CONST_TYPE_INFO_TYPE,
+  CPTI_GET_EXCEPTION_PTR_FN,
+  CPTI_BEGIN_CATCH_FN,
+  CPTI_END_CATCH_FN,
+  CPTI_ALLOCATE_EXCEPTION_FN,
+  CPTI_FREE_EXCEPTION_FN,
+  CPTI_THROW_FN,
+  CPTI_RETHROW_FN,
+  CPTI_ATEXIT_FN_PTR_TYPE,
+  CPTI_ATEXIT,
+  CPTI_DSO_HANDLE,
+  CPTI_DCAST,
+
+  CPTI_SOURCE_LOCATION_IMPL,
+
+  CPTI_FALLBACK_DFLOAT32_TYPE,
+  CPTI_FALLBACK_DFLOAT64_TYPE,
+  CPTI_FALLBACK_DFLOAT128_TYPE,
+
+  CPTI_MAX
+};
+
+// forked from gcc/cp/cp-tree.h cp_global_trees
+
+extern GTY (()) tree cp_global_trees[CPTI_MAX];
+
+#define wchar_decl_node cp_global_trees[CPTI_WCHAR_DECL]
+#define vtable_entry_type cp_global_trees[CPTI_VTABLE_ENTRY_TYPE]
+/* The type used to represent an offset by which to adjust the `this'
+   pointer in pointer-to-member types.  */
+#define delta_type_node cp_global_trees[CPTI_DELTA_TYPE]
+/* The type used to represent an index into the vtable.  */
+#define vtable_index_type cp_global_trees[CPTI_VTABLE_INDEX_TYPE]
+
+#define class_type_node cp_global_trees[CPTI_CLASS_TYPE]
+#define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE]
+#define init_list_type_node cp_global_trees[CPTI_INIT_LIST_TYPE]
+#define explicit_void_list_node cp_global_trees[CPTI_EXPLICIT_VOID_LIST]
+#define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE]
+#define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE]
+#define std_node cp_global_trees[CPTI_STD]
+#define abi_node cp_global_trees[CPTI_ABI]
+#define global_namespace cp_global_trees[CPTI_GLOBAL]
+#define const_type_info_type_node cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE]
+#define conv_op_marker cp_global_trees[CPTI_CONV_OP_MARKER]
+#define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL]
+#define current_aggr cp_global_trees[CPTI_AGGR_TAG]
+#define nullptr_node cp_global_trees[CPTI_NULLPTR]
+#define nullptr_type_node cp_global_trees[CPTI_NULLPTR_TYPE]
+/* std::align_val_t */
+#define align_type_node cp_global_trees[CPTI_ALIGN_TYPE]
+
+/* We cache these tree nodes so as to call get_identifier less frequently.
+   For identifiers for functions, including special member functions such
+   as ctors and assignment operators, the nodes can be used (among other
+   things) to iterate over their overloads defined by/for a type.  For
+   example:
+
+     tree ovlid = assign_op_identifier;
+     tree overloads = get_class_binding (type, ovlid);
+     for (ovl_iterator it (overloads); it; ++it) { ... }
+
+   iterates over the set of implicitly and explicitly defined overloads
+   of the assignment operator for type (including the copy and move
+   assignment operators, whether deleted or not).  */
+
+/* The name of a constructor that takes an in-charge parameter to
+   decide whether or not to construct virtual base classes.  */
+#define ctor_identifier cp_global_trees[CPTI_CTOR_IDENTIFIER]
+/* The name of a constructor that constructs virtual base classes.  */
+#define complete_ctor_identifier cp_global_trees[CPTI_COMPLETE_CTOR_IDENTIFIER]
+/* The name of a constructor that does not construct virtual base classes.  */
+#define base_ctor_identifier cp_global_trees[CPTI_BASE_CTOR_IDENTIFIER]
+/* The name of a destructor that takes an in-charge parameter to
+   decide whether or not to destroy virtual base classes and whether
+   or not to delete the object.  */
+#define dtor_identifier cp_global_trees[CPTI_DTOR_IDENTIFIER]
+/* The name of a destructor that destroys virtual base classes.  */
+#define complete_dtor_identifier cp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER]
+/* The name of a destructor that does not destroy virtual base
+   classes.  */
+#define base_dtor_identifier cp_global_trees[CPTI_BASE_DTOR_IDENTIFIER]
+/* The name of a destructor that destroys virtual base classes, and
+   then deletes the entire object.  */
+#define deleting_dtor_identifier cp_global_trees[CPTI_DELETING_DTOR_IDENTIFIER]
+
+/* The name used for conversion operators -- but note that actual
+   conversion functions use special identifiers outside the identifier
+   table.  */
+#define conv_op_identifier cp_global_trees[CPTI_CONV_OP_IDENTIFIER]
+
+#define delta_identifier cp_global_trees[CPTI_DELTA_IDENTIFIER]
+#define in_charge_identifier cp_global_trees[CPTI_IN_CHARGE_IDENTIFIER]
+/* The name of the parameter that contains a pointer to the VTT to use
+   for this subobject constructor or destructor.  */
+#define vtt_parm_identifier cp_global_trees[CPTI_VTT_PARM_IDENTIFIER]
+#define as_base_identifier cp_global_trees[CPTI_AS_BASE_IDENTIFIER]
+#define this_identifier cp_global_trees[CPTI_THIS_IDENTIFIER]
+#define pfn_identifier cp_global_trees[CPTI_PFN_IDENTIFIER]
+#define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER]
+/* The name of the ::, std & anon namespaces.  */
+#define global_identifier cp_global_trees[CPTI_GLOBAL_IDENTIFIER]
+#define anon_identifier cp_global_trees[CPTI_ANON_IDENTIFIER]
+/* auto and declspec(auto) identifiers.  */
+#define auto_identifier cp_global_trees[CPTI_AUTO_IDENTIFIER]
+#define decltype_auto_identifier cp_global_trees[CPTI_DECLTYPE_AUTO_IDENTIFIER]
+#define init_list_identifier cp_global_trees[CPTI_INIT_LIST_IDENTIFIER]
+#define for_range__identifier cp_global_trees[CPTI_FOR_RANGE__IDENTIFIER]
+#define for_begin__identifier cp_global_trees[CPTI_FOR_BEGIN__IDENTIFIER]
+#define for_end__identifier cp_global_trees[CPTI_FOR_END__IDENTIFIER]
+#define for_range_identifier cp_global_trees[CPTI_FOR_RANGE_IDENTIFIER]
+#define for_begin_identifier cp_global_trees[CPTI_FOR_BEGIN_IDENTIFIER]
+#define for_end_identifier cp_global_trees[CPTI_FOR_END_IDENTIFIER]
+#define abi_tag_identifier cp_global_trees[CPTI_ABI_TAG_IDENTIFIER]
+#define aligned_identifier cp_global_trees[CPTI_ALIGNED_IDENTIFIER]
+#define begin_identifier cp_global_trees[CPTI_BEGIN_IDENTIFIER]
+#define end_identifier cp_global_trees[CPTI_END_IDENTIFIER]
+#define get__identifier cp_global_trees[CPTI_GET_IDENTIFIER]
+#define gnu_identifier cp_global_trees[CPTI_GNU_IDENTIFIER]
+#define tuple_element_identifier cp_global_trees[CPTI_TUPLE_ELEMENT_IDENTIFIER]
+#define tuple_size_identifier cp_global_trees[CPTI_TUPLE_SIZE_IDENTIFIER]
+#define type_identifier cp_global_trees[CPTI_TYPE_IDENTIFIER]
+#define value_identifier cp_global_trees[CPTI_VALUE_IDENTIFIER]
+#define fun_identifier cp_global_trees[CPTI_FUN_IDENTIFIER]
+#define closure_identifier cp_global_trees[CPTI_CLOSURE_IDENTIFIER]
+#define heap_uninit_identifier cp_global_trees[CPTI_HEAP_UNINIT_IDENTIFIER]
+#define heap_identifier cp_global_trees[CPTI_HEAP_IDENTIFIER]
+#define heap_deleted_identifier cp_global_trees[CPTI_HEAP_DELETED_IDENTIFIER]
+#define heap_vec_uninit_identifier                                             \
+  cp_global_trees[CPTI_HEAP_VEC_UNINIT_IDENTIFIER]
+#define heap_vec_identifier cp_global_trees[CPTI_HEAP_VEC_IDENTIFIER]
+#define omp_identifier cp_global_trees[CPTI_OMP_IDENTIFIER]
+#define lang_name_c cp_global_trees[CPTI_LANG_NAME_C]
+#define lang_name_cplusplus cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
+
+/* Exception specifiers used for throw(), noexcept(true),
+   noexcept(false) and deferred noexcept.  We rely on these being
+   uncloned.  */
+#define empty_except_spec cp_global_trees[CPTI_EMPTY_EXCEPT_SPEC]
+#define noexcept_true_spec cp_global_trees[CPTI_NOEXCEPT_TRUE_SPEC]
+#define noexcept_false_spec cp_global_trees[CPTI_NOEXCEPT_FALSE_SPEC]
+#define noexcept_deferred_spec cp_global_trees[CPTI_NOEXCEPT_DEFERRED_SPEC]
+
+/* Exception handling function declarations.  */
+#define terminate_fn cp_global_trees[CPTI_TERMINATE_FN]
+#define call_unexpected_fn cp_global_trees[CPTI_CALL_UNEXPECTED_FN]
+#define get_exception_ptr_fn cp_global_trees[CPTI_GET_EXCEPTION_PTR_FN]
+#define begin_catch_fn cp_global_trees[CPTI_BEGIN_CATCH_FN]
+#define end_catch_fn cp_global_trees[CPTI_END_CATCH_FN]
+#define allocate_exception_fn cp_global_trees[CPTI_ALLOCATE_EXCEPTION_FN]
+#define free_exception_fn cp_global_trees[CPTI_FREE_EXCEPTION_FN]
+#define throw_fn cp_global_trees[CPTI_THROW_FN]
+#define rethrow_fn cp_global_trees[CPTI_RETHROW_FN]
+
+/* The type of the function-pointer argument to "__cxa_atexit" (or
+   "std::atexit", if "__cxa_atexit" is not being used).  */
+#define atexit_fn_ptr_type_node cp_global_trees[CPTI_ATEXIT_FN_PTR_TYPE]
+
+/* A pointer to `std::atexit'.  */
+#define atexit_node cp_global_trees[CPTI_ATEXIT]
+
+/* A pointer to `__dso_handle'.  */
+#define dso_handle_node cp_global_trees[CPTI_DSO_HANDLE]
+
+/* The declaration of the dynamic_cast runtime.  */
+#define dynamic_cast_node cp_global_trees[CPTI_DCAST]
+
+/* The type of a destructor.  */
+#define cleanup_type cp_global_trees[CPTI_CLEANUP_TYPE]
+
+/* The type of the vtt parameter passed to subobject constructors and
+   destructors.  */
+#define vtt_parm_type cp_global_trees[CPTI_VTT_PARM_TYPE]
+
+/* A node which matches any template argument.  */
+#define any_targ_node cp_global_trees[CPTI_ANY_TARG]
+
+/* std::source_location::__impl class.  */
+#define source_location_impl cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -477,6 +754,9 @@ rs_type_quals (const_tree type);
 
 extern bool decl_maybe_constant_var_p (tree);
 
+extern void
+init_modules ();
+
 extern tree
 rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *);
 #define rs_walk_tree(tp, func, data, pset)                                     \

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:33 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:bb4dd8fbc857a78bb4bfb69f1bdfdcbd9b1b6cdb

commit bb4dd8fbc857a78bb4bfb69f1bdfdcbd9b1b6cdb
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Tue Jul 19 17:39:56 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - decl_constant_var_p
     - undeduced_auto_decl
     - require_deduced_type
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 46 +++++++++++++++++++++++++++++++++++++++++++
 gcc/rust/backend/rust-tree.h  |  6 ++++++
 2 files changed, 52 insertions(+)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index e1ab7f16074..028d88f420c 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -3969,4 +3969,50 @@ retry:
     }
 }
 
+// forked from gcc/cp/decl2.cc decl_constant_var_p
+
+/* Nonzero for a VAR_DECL whose value can be used in a constant expression.
+
+      [expr.const]
+
+      An integral constant-expression can only involve ... const
+      variables of integral or enumeration types initialized with
+      constant expressions ...
+
+      C++0x also allows constexpr variables and temporaries initialized
+      with constant expressions.  We handle the former here, but the latter
+      are just folded away in cxx_eval_constant_expression.
+
+   The standard does not require that the expression be non-volatile.
+   G++ implements the proposed correction in DR 457.  */
+
+bool
+decl_constant_var_p (tree decl)
+{
+  if (!decl_maybe_constant_var_p (decl))
+    return false;
+
+  return DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl);
+}
+
+// forked from gcc/cp/decl.cc undeduced_auto_decl
+
+/* Returns true iff DECL is a variable or function declared with an auto type
+   that has not yet been deduced to a real type.  */
+
+bool
+undeduced_auto_decl (tree decl)
+{
+  return false;
+}
+
+// forked from gcc/cp/decl.cc require_deduced_type
+
+/* Complain if DECL has an undeduced return type.  */
+
+bool
+require_deduced_type (tree decl, tsubst_flags_t complain)
+{
+  return true;
+}
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index fc83dc2cb8f..624f9364bed 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2542,6 +2542,12 @@ extern void cxx_incomplete_type_inform (const_tree);
 
 extern tree strip_top_quals (tree);
 
+extern bool undeduced_auto_decl (tree);
+
+extern bool require_deduced_type (tree, tsubst_flags_t = tf_warning_or_error);
+
+extern bool decl_constant_var_p (tree);
+
 // forked from gcc/cp/cp-tree.h
 
 enum

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:33 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:121c8dd00de81ec9c11d494d402e4761dbe4fe4d

commit 121c8dd00de81ec9c11d494d402e4761dbe4fe4d
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Tue Jul 19 14:38:53 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - resolve_nondeduced_context
     - instantiate_non_dependent_or_null
     - resolve_nondeduced_context_or_error
     - really_overloaded_fn
     - invalid_nonstatic_memfn_p
     - strip_top_quals
     - cxx_incomplete_type_inform
     - cxx_incomplete_type_diagnostic
     - cxx_incomplete_type_error
    
    Following structs, classes and enums are ported in this changeset:
     - stmt_tree_s
     - c_language_function
     - omp_declare_target_attr
     - cxx_binding
     - cxx_saved_binding
     - saved_scope
     - named_label_hash
     - language_function
     - ref_operator
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 248 ++++++++++++++++++++++++++
 gcc/rust/backend/rust-tree.h  | 398 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 628 insertions(+), 18 deletions(-)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 22e91f4d828..e1ab7f16074 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -28,12 +28,17 @@
 #include "timevar.h"
 #include "convert.h"
 #include "gimple-expr.h"
+#include "gimplify.h"
+#include "function.h"
+#include "gcc-rich-location.h"
 
 // forked from gcc/c-family/c-common.cc c_global_trees
 tree c_global_trees[CTI_MAX];
 // forked from gcc/cp/decl.cc cp_global_trees
 tree cp_global_trees[CPTI_MAX];
 
+struct saved_scope *scope_chain;
+
 namespace Rust {
 
 void
@@ -3721,4 +3726,247 @@ resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain)
 
   return orig_expr;
 }
+
+// forked from gcc/cp/pt.cc instantiate_non_dependent_or_null
+
+/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
+   an uninstantiated expression.  */
+
+tree
+instantiate_non_dependent_or_null (tree expr)
+{
+  if (expr == NULL_TREE)
+    return NULL_TREE;
+
+  return expr;
+}
+
+// forked from gcc/cp/pt.cc resolve_nondeduced_context_or_error
+
+/* As above, but error out if the expression remains overloaded.  */
+
+tree
+resolve_nondeduced_context_or_error (tree exp, tsubst_flags_t complain)
+{
+  exp = resolve_nondeduced_context (exp, complain);
+  if (type_unknown_p (exp))
+    {
+      if (complain & tf_error)
+	cxx_incomplete_type_error (exp, TREE_TYPE (exp));
+      return error_mark_node;
+    }
+  return exp;
+}
+
+// forked from gcc/cp/tree.cc really_overloaded_fn
+
+/* Returns true iff X is an expression for an overloaded function
+   whose type cannot be known without performing overload
+   resolution.  */
+
+bool
+really_overloaded_fn (tree x)
+{
+  return is_overloaded_fn (x) == 2;
+}
+
+// forked from gcc/cp/typeck..cc invalid_nonstatic_memfn_p
+
+/* EXPR is being used in a context that is not a function call.
+   Enforce:
+
+     [expr.ref]
+
+     The expression can be used only as the left-hand operand of a
+     member function call.
+
+     [expr.mptr.operator]
+
+     If the result of .* or ->* is a function, then that result can be
+     used only as the operand for the function call operator ().
+
+   by issuing an error message if appropriate.  Returns true iff EXPR
+   violates these rules.  */
+
+bool
+invalid_nonstatic_memfn_p (location_t loc, tree expr, tsubst_flags_t complain)
+{
+  if (expr == NULL_TREE)
+    return false;
+  /* Don't enforce this in MS mode.  */
+  if (flag_ms_extensions)
+    return false;
+  if (is_overloaded_fn (expr) && !really_overloaded_fn (expr))
+    expr = get_first_fn (expr);
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (expr))
+    {
+      if (complain & tf_error)
+	{
+	  if (DECL_P (expr))
+	    {
+	      error_at (loc, "invalid use of non-static member function %qD",
+			expr);
+	      inform (DECL_SOURCE_LOCATION (expr), "declared here");
+	    }
+	  else
+	    error_at (loc,
+		      "invalid use of non-static member function of "
+		      "type %qT",
+		      TREE_TYPE (expr));
+	}
+      return true;
+    }
+  return false;
+}
+
+// forked from gcc/cp/call.cc strip_top_quals
+
+tree
+strip_top_quals (tree t)
+{
+  if (TREE_CODE (t) == ARRAY_TYPE)
+    return t;
+  return rs_build_qualified_type (t, 0);
+}
+
+// forked from gcc/cp/typeck2.cc cxx_incomplete_type_inform
+
+/* Print an inform about the declaration of the incomplete type TYPE.  */
+
+void
+cxx_incomplete_type_inform (const_tree type)
+{
+  if (!TYPE_MAIN_DECL (type))
+    return;
+
+  location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type));
+  tree ptype = strip_top_quals (CONST_CAST_TREE (type));
+
+  if (current_class_type && TYPE_BEING_DEFINED (current_class_type)
+      && same_type_p (ptype, current_class_type))
+    inform (loc,
+	    "definition of %q#T is not complete until "
+	    "the closing brace",
+	    ptype);
+  else
+    inform (loc, "forward declaration of %q#T", ptype);
+}
+
+// forked from gcc/cp/typeck2.cc cxx_incomplete_type_diagnostic
+
+/* Print an error message for invalid use of an incomplete type.
+   VALUE is the expression that was used (or 0 if that isn't known)
+   and TYPE is the type that was invalid.  DIAG_KIND indicates the
+   type of diagnostic (see diagnostic.def).  */
+
+void
+cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
+				const_tree type, diagnostic_t diag_kind)
+{
+  bool is_decl = false, complained = false;
+
+  gcc_assert (diag_kind == DK_WARNING || diag_kind == DK_PEDWARN
+	      || diag_kind == DK_ERROR);
+
+  /* Avoid duplicate error message.  */
+  if (TREE_CODE (type) == ERROR_MARK)
+    return;
+
+  if (value)
+    {
+      STRIP_ANY_LOCATION_WRAPPER (value);
+
+      if (VAR_P (value) || TREE_CODE (value) == PARM_DECL
+	  || TREE_CODE (value) == FIELD_DECL)
+	{
+	  complained = emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION (value),
+					0, "%qD has incomplete type", value);
+	  is_decl = true;
+	}
+    }
+retry:
+  /* We must print an error message.  Be clever about what it says.  */
+
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case ENUMERAL_TYPE:
+      if (!is_decl)
+	complained
+	  = emit_diagnostic (diag_kind, loc, 0,
+			     "invalid use of incomplete type %q#T", type);
+      if (complained)
+	cxx_incomplete_type_inform (type);
+      break;
+
+    case VOID_TYPE:
+      emit_diagnostic (diag_kind, loc, 0, "invalid use of %qT", type);
+      break;
+
+    case ARRAY_TYPE:
+      if (TYPE_DOMAIN (type))
+	{
+	  type = TREE_TYPE (type);
+	  goto retry;
+	}
+      emit_diagnostic (diag_kind, loc, 0,
+		       "invalid use of array with unspecified bounds");
+      break;
+
+    case OFFSET_TYPE:
+      bad_member : {
+	tree member = TREE_OPERAND (value, 1);
+	if (is_overloaded_fn (member))
+	  member = get_first_fn (member);
+
+	if (DECL_FUNCTION_MEMBER_P (member) && !flag_ms_extensions)
+	  {
+	    gcc_rich_location richloc (loc);
+	    /* If "member" has no arguments (other than "this"), then
+	       add a fix-it hint.  */
+	    if (type_num_arguments (TREE_TYPE (member)) == 1)
+	      richloc.add_fixit_insert_after ("()");
+	    emit_diagnostic (diag_kind, &richloc, 0,
+			     "invalid use of member function %qD "
+			     "(did you forget the %<()%> ?)",
+			     member);
+	  }
+	else
+	  emit_diagnostic (diag_kind, loc, 0,
+			   "invalid use of member %qD "
+			   "(did you forget the %<&%> ?)",
+			   member);
+      }
+      break;
+
+    case LANG_TYPE:
+      if (type == init_list_type_node)
+	{
+	  emit_diagnostic (diag_kind, loc, 0,
+			   "invalid use of brace-enclosed initializer list");
+	  break;
+	}
+      gcc_assert (type == unknown_type_node);
+      if (value && TREE_CODE (value) == COMPONENT_REF)
+	goto bad_member;
+      else if (value && TREE_CODE (value) == ADDR_EXPR)
+	emit_diagnostic (diag_kind, loc, 0,
+			 "address of overloaded function with no contextual "
+			 "type information");
+      else if (value && TREE_CODE (value) == OVERLOAD)
+	emit_diagnostic (
+	  diag_kind, loc, 0,
+	  "overloaded function with no contextual type information");
+      else
+	emit_diagnostic (
+	  diag_kind, loc, 0,
+	  "insufficient contextual information to determine type");
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 9e8de7cf833..fc83dc2cb8f 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -1098,6 +1098,148 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 /* Returns true if NODE is a pointer or a pointer-to-member.  */
 #define TYPE_PTR_OR_PTRMEM_P(NODE) (TYPE_PTR_P (NODE) || TYPE_PTRMEM_P (NODE))
 
+/* Nonzero if NODE is an artificial VAR_DECL for a C++17 structured binding
+   declaration or one of VAR_DECLs for the user identifiers in it.  */
+#define DECL_DECOMPOSITION_P(NODE)                                             \
+  (VAR_P (NODE) && DECL_LANG_SPECIFIC (NODE)                                   \
+     ? DECL_LANG_SPECIFIC (NODE)->u.base.selector == lds_decomp                \
+     : false)
+
+/* The underlying artificial VAR_DECL for structured binding.  */
+#define DECL_DECOMP_BASE(NODE) (LANG_DECL_DECOMP_CHECK (NODE)->base)
+
+/* Nonzero if either DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P or
+   DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P is true of NODE.  */
+#define DECL_MAYBE_IN_CHARGE_CDTOR_P(NODE)                                     \
+  (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (NODE)                                   \
+   || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (NODE))
+
+/* Nonzero if NODE (a FUNCTION_DECL) is a destructor, but not the
+   specialized in-charge constructor, in-charge deleting constructor,
+   or the base destructor.  */
+#define DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P(NODE)                                \
+  (DECL_NAME (NODE) == dtor_identifier)
+
+/* Nonzero if NODE (a _DECL) is a cloned constructor or
+   destructor.  */
+#define DECL_CLONED_FUNCTION_P(NODE)                                           \
+  (DECL_NAME (NODE) && IDENTIFIER_CDTOR_P (DECL_NAME (NODE))                   \
+   && !DECL_MAYBE_IN_CHARGE_CDTOR_P (NODE))
+
+/* If DECL_CLONED_FUNCTION_P holds, this is the function that was
+   cloned.  */
+#define DECL_CLONED_FUNCTION(NODE)                                             \
+  (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))->u.fn.u5.cloned_function)
+
+/* Nonzero if NODE (a _DECL) is a cloned constructor or
+   destructor.  */
+#define DECL_CLONED_FUNCTION_P(NODE)                                           \
+  (DECL_NAME (NODE) && IDENTIFIER_CDTOR_P (DECL_NAME (NODE))                   \
+   && !DECL_MAYBE_IN_CHARGE_CDTOR_P (NODE))
+
+/* Nonzero if NODE (a FUNCTION_DECL) is a constructor, but not either the
+   specialized in-charge constructor or the specialized not-in-charge
+   constructor.  */
+#define DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P(NODE)                               \
+  (DECL_NAME (NODE) == ctor_identifier)
+
+/* The current C++-specific per-function global variables.  */
+
+#define cp_function_chain (cfun->language)
+
+/* In a constructor destructor, the point at which all derived class
+   destroying/construction has been done.  I.e., just before a
+   constructor returns, or before any base class destroying will be done
+   in a destructor.  */
+
+#define cdtor_label cp_function_chain->x_cdtor_label
+
+/* When we're processing a member function, current_class_ptr is the
+   PARM_DECL for the `this' pointer.  The current_class_ref is an
+   expression for `*this'.  */
+
+#define current_class_ptr                                                      \
+  (*(cfun && cp_function_chain ? &cp_function_chain->x_current_class_ptr       \
+			       : &scope_chain->x_current_class_ptr))
+#define current_class_ref                                                      \
+  (*(cfun && cp_function_chain ? &cp_function_chain->x_current_class_ref       \
+			       : &scope_chain->x_current_class_ref))
+
+/* The EH_SPEC_BLOCK for the exception-specifiers for the current
+   function, if any.  */
+
+#define current_eh_spec_block cp_function_chain->x_eh_spec_block
+
+/* The `__in_chrg' parameter for the current function.  Only used for
+   constructors and destructors.  */
+
+#define current_in_charge_parm cp_function_chain->x_in_charge_parm
+
+/* The `__vtt_parm' parameter for the current function.  Only used for
+   constructors and destructors.  */
+
+#define current_vtt_parm cp_function_chain->x_vtt_parm
+
+/* A boolean flag to control whether we need to clean up the return value if a
+   local destructor throws.  Only used in functions that return by value a
+   class with a destructor.  Which 'tors don't, so we can use the same
+   field as current_vtt_parm.  */
+
+#define current_retval_sentinel current_vtt_parm
+
+/* Set to 0 at beginning of a function definition, set to 1 if
+   a return statement that specifies a return value is seen.  */
+
+#define current_function_returns_value cp_function_chain->returns_value
+
+/* Set to 0 at beginning of a function definition, set to 1 if
+   a return statement with no argument is seen.  */
+
+#define current_function_returns_null cp_function_chain->returns_null
+
+/* Set to 0 at beginning of a function definition, set to 1 if
+   a call to a noreturn function is seen.  */
+
+#define current_function_returns_abnormally                                    \
+  cp_function_chain->returns_abnormally
+
+/* Set to 0 at beginning of a function definition, set to 1 if we see an
+   obvious infinite loop.  This can have false positives and false
+   negatives, so it should only be used as a heuristic.  */
+
+#define current_function_infinite_loop cp_function_chain->infinite_loop
+
+/* Nonzero if we are processing a base initializer.  Zero elsewhere.  */
+#define in_base_initializer cp_function_chain->x_in_base_initializer
+
+#define in_function_try_handler cp_function_chain->x_in_function_try_handler
+
+/* Expression always returned from function, or error_mark_node
+   otherwise, for use by the automatic named return value optimization.  */
+
+#define current_function_return_value (cp_function_chain->x_return_value)
+
+#define current_class_type scope_chain->class_type
+
+/* Nonzero means that this type is being defined.  I.e., the left brace
+   starting the definition of this type has been seen.  */
+#define TYPE_BEING_DEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->being_defined)
+
+/* Nonzero for FUNCTION_DECL means that this decl is a static
+   member function.  */
+#define DECL_STATIC_FUNCTION_P(NODE)                                           \
+  (LANG_DECL_FN_CHECK (NODE)->static_function)
+
+/* Nonzero for FUNCTION_DECL means that this decl is a non-static
+   member function.  */
+#define DECL_NONSTATIC_MEMBER_FUNCTION_P(NODE)                                 \
+  (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+
+/* Nonzero for FUNCTION_DECL means that this decl is a member function
+   (static or non-static).  */
+#define DECL_FUNCTION_MEMBER_P(NODE)                                           \
+  (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) || DECL_STATIC_FUNCTION_P (NODE))
+
 #if defined ENABLE_TREE_CHECKING
 
 #define LANG_DECL_MIN_CHECK(NODE)                                              \
@@ -1362,6 +1504,213 @@ struct GTY (()) lang_decl_base
    || TREE_CODE (NODE) == TEMPLATE_DECL || TREE_CODE (NODE) == USING_DECL      \
    || TREE_CODE (NODE) == CONCEPT_DECL)
 
+// forked from gcc/c-family-common.h stmt_tree_s
+
+/* Information about a statement tree.  */
+
+struct GTY (()) stmt_tree_s
+{
+  /* A stack of statement lists being collected.  */
+  vec<tree, va_gc> *x_cur_stmt_list;
+
+  /* In C++, Nonzero if we should treat statements as full
+     expressions.  In particular, this variable is non-zero if at the
+     end of a statement we should destroy any temporaries created
+     during that statement.  Similarly, if, at the end of a block, we
+     should destroy any local variables in this block.  Normally, this
+     variable is nonzero, since those are the normal semantics of
+     C++.
+
+     This flag has no effect in C.  */
+  int stmts_are_full_exprs_p;
+};
+
+// forked from gcc/c-family-common.h stmt_tree_s
+
+typedef struct stmt_tree_s *stmt_tree;
+
+// forked from gcc/c-family-common.h c_language_function
+
+/* Global state pertinent to the current function.  Some C dialects
+   extend this structure with additional fields.  */
+
+struct GTY (()) c_language_function
+{
+  /* While we are parsing the function, this contains information
+     about the statement-tree that we are building.  */
+  struct stmt_tree_s x_stmt_tree;
+
+  /* Vector of locally defined typedefs, for
+     -Wunused-local-typedefs.  */
+  vec<tree, va_gc> *local_typedefs;
+};
+
+// forked from gcc/cp/cp-tree.h omp_declare_target_attr
+
+struct GTY (()) omp_declare_target_attr
+{
+  bool attr_syntax;
+};
+
+// forked from gcc/cp/name-lookup.h cxx_binding
+
+/* Datatype that represents binding established by a declaration between
+   a name and a C++ entity.  */
+struct GTY (()) cxx_binding
+{
+  /* Link to chain together various bindings for this name.  */
+  cxx_binding *previous;
+  /* The non-type entity this name is bound to.  */
+  tree value;
+  /* The type entity this name is bound to.  */
+  tree type;
+
+  bool value_is_inherited : 1;
+  bool is_local : 1;
+  bool type_is_hidden : 1;
+};
+
+// forked from gcc/cp/name-lookup.h cxx_saved_binding
+
+/* Datatype used to temporarily save C++ bindings (for implicit
+   instantiations purposes and like).  Implemented in decl.cc.  */
+struct GTY (()) cxx_saved_binding
+{
+  /* The name of the current binding.  */
+  tree identifier;
+  /* The binding we're saving.  */
+  cxx_binding *binding;
+  tree real_type_value;
+};
+
+// forked from gcc/cp/cp-tree.h saved_scope
+
+/* Global state.  */
+
+struct GTY (()) saved_scope
+{
+  vec<cxx_saved_binding, va_gc> *old_bindings;
+  tree old_namespace;
+  vec<tree, va_gc> *decl_ns_list;
+  tree class_name;
+  tree class_type;
+  tree access_specifier;
+  tree function_decl;
+  vec<tree, va_gc> *lang_base;
+  tree lang_name;
+  tree template_parms;
+  tree x_saved_tree;
+
+  /* Only used for uses of this in trailing return type.  */
+  tree x_current_class_ptr;
+  tree x_current_class_ref;
+
+  int x_processing_template_decl;
+  int x_processing_specialization;
+  int x_processing_constraint;
+  int suppress_location_wrappers;
+  BOOL_BITFIELD x_processing_explicit_instantiation : 1;
+  BOOL_BITFIELD need_pop_function_context : 1;
+
+  /* Nonzero if we are parsing the discarded statement of a constexpr
+     if-statement.  */
+  BOOL_BITFIELD discarded_stmt : 1;
+  /* Nonzero if we are parsing or instantiating the compound-statement
+     of consteval if statement.  Also set while processing an immediate
+     invocation.  */
+  BOOL_BITFIELD consteval_if_p : 1;
+
+  int unevaluated_operand;
+  int inhibit_evaluation_warnings;
+  int noexcept_operand;
+  int ref_temp_count;
+
+  struct stmt_tree_s x_stmt_tree;
+
+  hash_map<tree, tree> *GTY ((skip)) x_local_specializations;
+  vec<omp_declare_target_attr, va_gc> *omp_declare_target_attribute;
+
+  struct saved_scope *prev;
+};
+
+extern GTY (()) struct saved_scope *scope_chain;
+
+// forked from gcc/cp/cp-tree.h named_label_hash
+
+struct named_label_entry; /* Defined in decl.cc.  */
+
+struct named_label_hash : ggc_remove<named_label_entry *>
+{
+  typedef named_label_entry *value_type;
+  typedef tree compare_type; /* An identifier.  */
+
+  inline static hashval_t hash (value_type);
+  inline static bool equal (const value_type, compare_type);
+
+  static const bool empty_zero_p = true;
+  inline static void mark_empty (value_type &p) { p = NULL; }
+  inline static bool is_empty (value_type p) { return !p; }
+
+  /* Nothing is deletable.  Everything is insertable.  */
+  inline static bool is_deleted (value_type) { return false; }
+  inline static void mark_deleted (value_type) { gcc_unreachable (); }
+};
+
+// forked from gcc/cp/cp-tree.h
+
+/* Global state pertinent to the current function.  */
+
+struct GTY (()) language_function
+{
+  struct c_language_function base;
+
+  tree x_cdtor_label;
+  tree x_current_class_ptr;
+  tree x_current_class_ref;
+  tree x_eh_spec_block;
+  tree x_in_charge_parm;
+  tree x_vtt_parm;
+  tree x_return_value;
+
+  BOOL_BITFIELD returns_value : 1;
+  BOOL_BITFIELD returns_null : 1;
+  BOOL_BITFIELD returns_abnormally : 1;
+  BOOL_BITFIELD infinite_loop : 1;
+  BOOL_BITFIELD x_in_function_try_handler : 1;
+  BOOL_BITFIELD x_in_base_initializer : 1;
+
+  /* True if this function can throw an exception.  */
+  BOOL_BITFIELD can_throw : 1;
+
+  BOOL_BITFIELD invalid_constexpr : 1;
+  BOOL_BITFIELD throwing_cleanup : 1;
+
+  hash_table<named_label_hash> *x_named_labels;
+
+  /* Tracking possibly infinite loops.  This is a vec<tree> only because
+     vec<bool> doesn't work with gtype.  */
+  vec<tree, va_gc> *infinite_loops;
+};
+
+// forked from gcc/c-family/c-common.h ref_operator
+
+/* The various name of operator that appears in error messages. */
+enum ref_operator
+{
+  /* NULL */
+  RO_NULL,
+  /* array indexing */
+  RO_ARRAY_INDEXING,
+  /* unary * */
+  RO_UNARY_STAR,
+  /* -> */
+  RO_ARROW,
+  /* implicit conversion */
+  RO_IMPLICIT_CONVERSION,
+  /* ->* */
+  RO_ARROW_STAR
+};
+
 // forked from gcc/cp/cp-tree.h lang_decl_min
 
 /* DECL_LANG_SPECIFIC for the above codes.  */
@@ -1530,24 +1879,6 @@ struct c_fileinfo
   short interface_unknown;
 };
 
-// forked from gcc/cp/name-lookup.h
-
-/* Datatype that represents binding established by a declaration between
-   a name and a C++ entity.  */
-struct GTY (()) cxx_binding
-{
-  /* Link to chain together various bindings for this name.  */
-  cxx_binding *previous;
-  /* The non-type entity this name is bound to.  */
-  tree value;
-  /* The type entity this name is bound to.  */
-  tree type;
-
-  bool value_is_inherited : 1;
-  bool is_local : 1;
-  bool type_is_hidden : 1;
-};
-
 // forked from gcc/c-family/c-common.h c_common_identifier
 
 /* Identifier part common to the C front ends.  Inherits from
@@ -2194,6 +2525,23 @@ extern bool reject_gcc_builtin (const_tree, location_t = UNKNOWN_LOCATION);
 
 extern tree resolve_nondeduced_context (tree, tsubst_flags_t);
 
+extern void cxx_incomplete_type_diagnostic (location_t, const_tree, const_tree,
+					    diagnostic_t);
+
+extern void cxx_incomplete_type_error (location_t, const_tree, const_tree);
+
+extern bool invalid_nonstatic_memfn_p (location_t, tree, tsubst_flags_t);
+
+extern bool really_overloaded_fn (tree) ATTRIBUTE_PURE;
+
+extern tree resolve_nondeduced_context_or_error (tree, tsubst_flags_t);
+
+extern tree instantiate_non_dependent_or_null (tree);
+
+extern void cxx_incomplete_type_inform (const_tree);
+
+extern tree strip_top_quals (tree);
+
 // forked from gcc/cp/cp-tree.h
 
 enum
@@ -2362,6 +2710,20 @@ null_node_p (const_tree expr)
   return expr == null_node;
 }
 
+inline void
+cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
+				diagnostic_t diag_kind)
+{
+  cxx_incomplete_type_diagnostic (rs_expr_loc_or_input_loc (value), value, type,
+				  diag_kind);
+}
+
+inline void
+cxx_incomplete_type_error (const_tree value, const_tree type)
+{
+  cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+}
+
 } // namespace Rust
 
 #endif // RUST_TREE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a00b61e6bfc4a79af55236db0e602e09cd8fda72

commit a00b61e6bfc4a79af55236db0e602e09cd8fda72
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Mon Jul 18 16:07:22 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - find_heap_var_refs
     - find_immediate_fndecl
     - instantiation_dependent_expression_p
     - cp_get_callee
     - build_nop
     - scalarish_type_p
     - type_has_nontrivial_copy_init
     - build_local_temp
     - is_normal_capture_proxy
     - reject_gcc_builtin
     - is_bitfield_expr_with_lowered_type
     - maybe_undo_parenthesized_ref
     - fold_offsetof
     - char_type_p
     - resolve_nondeduced_context
     - null_node_p
    
    Following structs, classes and enums are ported in this changeset:
     - c_tree_index
     - warning_sentinel
     - uid_sensitive_constexpr_evaluation_checker
     - iloc_sentinel
     - ptrmem_cst
    
    This changeset puts c_global_trees and cp_global_trees outside Rust and Compile
    namespaces because keeping them inside is causing build issues.
    This is possibly because rust-tree.cc contains only Rust namespace while
    rust-constexpr.cc is Rust+Compile namespace. This causes issues when trying to use
    them inside both files.
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-constexpr.cc | 105 +++++++-
 gcc/rust/backend/rust-tree.cc      | 501 ++++++++++++++++++++++++++++++++++++-
 gcc/rust/backend/rust-tree.h       | 304 +++++++++++++++++++++-
 3 files changed, 899 insertions(+), 11 deletions(-)

diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 8fb378fbda5..189badabf94 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -25,7 +25,9 @@
 #include "print-tree.h"
 #include "gimplify.h"
 #include "tree-iterator.h"
+#include "timevar.h"
 #include "varasm.h"
+#include "cgraph.h"
 
 #define VERIFY_CONSTANT(X)                                                     \
   do                                                                           \
@@ -50,6 +52,11 @@ struct constexpr_global_ctx
 {
   HOST_WIDE_INT constexpr_ops_count;
 
+  /* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR.  */
+  vec<tree> *cleanups;
+  /* Heap VAR_DECLs created during the evaluation of the outermost constant
+     expression.  */
+  auto_vec<tree, 16> heap_vars;
   constexpr_global_ctx () : constexpr_ops_count (0) {}
 };
 
@@ -481,6 +488,60 @@ var_in_maybe_constexpr_fn (tree t)
 
 // forked from gcc/cp/constexpr.cc array_index_cmp
 
+/* Some of the expressions fed to the constexpr mechanism are calls to
+   constructors, which have type void.  In that case, return the type being
+   initialized by the constructor.  */
+
+static tree
+initialized_type (tree t)
+{
+  if (TYPE_P (t))
+    return t;
+  tree type = TREE_TYPE (t);
+  if (TREE_CODE (t) == CALL_EXPR)
+    {
+      /* A constructor call has void type, so we need to look deeper.  */
+      tree fn = get_function_named_in_call (t);
+      if (fn && TREE_CODE (fn) == FUNCTION_DECL && DECL_CXX_CONSTRUCTOR_P (fn))
+	type = DECL_CONTEXT (fn);
+    }
+  else if (TREE_CODE (t) == COMPOUND_EXPR)
+    return initialized_type (TREE_OPERAND (t, 1));
+
+  return cv_unqualified (type);
+}
+
+/* P0859: A function is needed for constant evaluation if it is a constexpr
+   function that is named by an expression ([basic.def.odr]) that is
+   potentially constant evaluated.
+
+   So we need to instantiate any constexpr functions mentioned by the
+   expression even if the definition isn't needed for evaluating the
+   expression.  */
+
+static tree
+instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void * /*data*/)
+{
+  if (TREE_CODE (*tp) == CALL_EXPR)
+    {
+      if (EXPR_HAS_LOCATION (*tp))
+	input_location = EXPR_LOCATION (*tp);
+    }
+
+  if (!EXPR_P (*tp))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
+static void
+instantiate_constexpr_fns (tree t)
+{
+  location_t loc = input_location;
+  rs_walk_tree_without_duplicates (&t, instantiate_cx_fn_r, NULL);
+  input_location = loc;
+}
+
 /* Returns less than, equal to, or greater than zero if KEY is found to be
    less than, to match, or to be greater than the constructor_elt's INDEX.  */
 
@@ -508,8 +569,6 @@ array_index_cmp (tree key, tree index)
     }
 }
 
-// forked from gcc/cp/constexpr.cc unshare_constructor
-
 /* If T is a CONSTRUCTOR, return an unshared copy of T and any
    sub-CONSTRUCTORs.  Otherwise return T.
 
@@ -540,8 +599,6 @@ unshare_constructor (tree t MEM_STAT_DECL)
   return t;
 }
 
-// forked from gcc/cp/constexpr.cc find_array_ctor_elt
-
 /* Returns the index of the constructor_elt of ARY which matches DINDEX, or -1
    if none.  If INSERT is true, insert a matching element rather than fail.  */
 
@@ -666,8 +723,6 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert)
   return -1;
 }
 
-// forked from gcc/cp/constexpr.cc reduced_constant_expression_p
-
 /* Return true if T is a valid constant initializer.  If a CONSTRUCTOR
    initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be
    cleared.
@@ -758,8 +813,6 @@ reduced_constant_expression_p (tree t)
     }
 }
 
-// forked from gcc/cp/constexpr.cc verify_constant
-
 /* Some expressions may have constant operands but are not constant
    themselves, such as 1/0.  Call this function to check for that
    condition.
@@ -794,6 +847,42 @@ verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
   return *non_constant_p;
 }
 
+// forked from gcc/cp/constexpr.cc find_heap_var_refs
+
+/* Look for heap variables in the expression *TP.  */
+
+static tree
+find_heap_var_refs (tree *tp, int *walk_subtrees, void * /*data*/)
+{
+  if (VAR_P (*tp)
+      && (DECL_NAME (*tp) == heap_uninit_identifier
+	  || DECL_NAME (*tp) == heap_identifier
+	  || DECL_NAME (*tp) == heap_vec_uninit_identifier
+	  || DECL_NAME (*tp) == heap_vec_identifier
+	  || DECL_NAME (*tp) == heap_deleted_identifier))
+    return *tp;
+
+  if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/constexpr.cc find_immediate_fndecl
+
+/* Find immediate function decls in *TP if any.  */
+
+static tree
+find_immediate_fndecl (tree *tp, int * /*walk_subtrees*/, void * /*data*/)
+{
+  if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp))
+    return *tp;
+  if (TREE_CODE (*tp) == PTRMEM_CST
+      && TREE_CODE (PTRMEM_CST_MEMBER (*tp)) == FUNCTION_DECL
+      && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (*tp)))
+    return PTRMEM_CST_MEMBER (*tp);
+  return NULL_TREE;
+}
+
 // forked in gcc/cp/constexpr.cc diag_array_subscript
 
 /* Under the control of CTX, issue a detailed diagnostic for
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 9221f7bb081..22e91f4d828 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -26,6 +26,13 @@
 #include "hash-map.h"
 #include "diagnostic.h"
 #include "timevar.h"
+#include "convert.h"
+#include "gimple-expr.h"
+
+// forked from gcc/c-family/c-common.cc c_global_trees
+tree c_global_trees[CTI_MAX];
+// forked from gcc/cp/decl.cc cp_global_trees
+tree cp_global_trees[CPTI_MAX];
 
 namespace Rust {
 
@@ -995,7 +1002,115 @@ rs_type_quals (const_tree type)
 	tree type_info_type_node, tinfo_decl_id, tinfo_decl_type;
 	tree tinfo_var_id;  */
 
-tree cp_global_trees[CPTI_MAX];
+/* The following symbols are subsumed in the c_global_trees array, and
+   listed here individually for documentation purposes.
+
+   INTEGER_TYPE and REAL_TYPE nodes for the standard data types.
+
+	tree short_integer_type_node;
+	tree long_integer_type_node;
+	tree long_long_integer_type_node;
+
+	tree short_unsigned_type_node;
+	tree long_unsigned_type_node;
+	tree long_long_unsigned_type_node;
+
+	tree truthvalue_type_node;
+	tree truthvalue_false_node;
+	tree truthvalue_true_node;
+
+	tree ptrdiff_type_node;
+
+	tree unsigned_char_type_node;
+	tree signed_char_type_node;
+	tree wchar_type_node;
+
+	tree char8_type_node;
+	tree char16_type_node;
+	tree char32_type_node;
+
+	tree float_type_node;
+	tree double_type_node;
+	tree long_double_type_node;
+
+	tree complex_integer_type_node;
+	tree complex_float_type_node;
+	tree complex_double_type_node;
+	tree complex_long_double_type_node;
+
+	tree dfloat32_type_node;
+	tree dfloat64_type_node;
+	tree_dfloat128_type_node;
+
+	tree intQI_type_node;
+	tree intHI_type_node;
+	tree intSI_type_node;
+	tree intDI_type_node;
+	tree intTI_type_node;
+
+	tree unsigned_intQI_type_node;
+	tree unsigned_intHI_type_node;
+	tree unsigned_intSI_type_node;
+	tree unsigned_intDI_type_node;
+	tree unsigned_intTI_type_node;
+
+	tree widest_integer_literal_type_node;
+	tree widest_unsigned_literal_type_node;
+
+   Nodes for types `void *' and `const void *'.
+
+	tree ptr_type_node, const_ptr_type_node;
+
+   Nodes for types `char *' and `const char *'.
+
+	tree string_type_node, const_string_type_node;
+
+   Type `char[SOMENUMBER]'.
+   Used when an array of char is needed and the size is irrelevant.
+
+	tree char_array_type_node;
+
+   Type `wchar_t[SOMENUMBER]' or something like it.
+   Used when a wide string literal is created.
+
+	tree wchar_array_type_node;
+
+   Type `char8_t[SOMENUMBER]' or something like it.
+   Used when a UTF-8 string literal is created.
+
+	tree char8_array_type_node;
+
+   Type `char16_t[SOMENUMBER]' or something like it.
+   Used when a UTF-16 string literal is created.
+
+	tree char16_array_type_node;
+
+   Type `char32_t[SOMENUMBER]' or something like it.
+   Used when a UTF-32 string literal is created.
+
+	tree char32_array_type_node;
+
+   Type `int ()' -- used for implicit declaration of functions.
+
+	tree default_function_type;
+
+   A VOID_TYPE node, packaged in a TREE_LIST.
+
+	tree void_list_node;
+
+  The lazily created VAR_DECLs for __FUNCTION__, __PRETTY_FUNCTION__,
+  and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__
+  VAR_DECLS, but C++ does.)
+
+	tree function_name_decl_node;
+	tree pretty_function_name_decl_node;
+	tree c99_function_name_decl_node;
+
+  Stack of nested function name VAR_DECLs.
+
+	tree saved_function_name_decls;
+
+*/
 
 // forked from gcc/cp/module.cc fixed_trees
 
@@ -1035,6 +1150,7 @@ maybe_add_global (tree val, unsigned &crc)
 /* Global trees.  */
 static const std::pair<tree *, unsigned> global_tree_arys[] = {
   std::pair<tree *, unsigned> (cp_global_trees, CPTI_MODULE_HWM),
+  std::pair<tree *, unsigned> (c_global_trees, CTI_MODULE_HWM),
 };
 
 // forked from gcc/cp/module.cc init_modules
@@ -1051,6 +1167,13 @@ init_modules ()
     {
       maybe_add_global (*ptr, crc);
     }
+
+  ptr = global_tree_arys[1].first;
+  limit = global_tree_arys[1].second;
+  for (unsigned ix = 0; ix != limit; ix++, ptr++)
+    {
+      maybe_add_global (*ptr, crc);
+    }
 }
 
 // forked from gcc/cp/constexpr.cc var_in_constexpr_fn
@@ -3222,4 +3345,380 @@ release_tree_vector (vec<tree, va_gc> *vec)
 	}
     }
 }
+
+// forked from gcc/cp/cvt.cc instantiation_dependent_expression_p
+
+/* As above, but also check value-dependence of the expression as a whole.  */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+  return false;
+}
+
+// forked from gcc/cp/cvt.cc cp_get_callee
+
+/* If CALL is a call, return the callee; otherwise null.  */
+
+tree
+cp_get_callee (tree call)
+{
+  if (call == NULL_TREE)
+    return call;
+  else if (TREE_CODE (call) == CALL_EXPR)
+    return CALL_EXPR_FN (call);
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/typeck.cc build_nop
+
+/* Return a NOP_EXPR converting EXPR to TYPE.  */
+
+tree
+build_nop (tree type, tree expr)
+{
+  if (type == error_mark_node || error_operand_p (expr))
+    return expr;
+  return build1_loc (EXPR_LOCATION (expr), NOP_EXPR, type, expr);
+}
+
+// forked from gcc/cp/tree.cc scalarish_type_p
+
+/* Returns 1 iff type T is something we want to treat as a scalar type for
+   the purpose of deciding whether it is trivial/POD/standard-layout.  */
+
+bool
+scalarish_type_p (const_tree t)
+{
+  if (t == error_mark_node)
+    return 1;
+
+  return (SCALAR_TYPE_P (t) || VECTOR_TYPE_P (t));
+}
+
+// forked from gcc/cp/tree.cc type_has_nontrivial_copy_init
+
+/* Returns true iff copying an object of type T (including via move
+   constructor) is non-trivial.  That is, T has no non-trivial copy
+   constructors and no non-trivial move constructors, and not all copy/move
+   constructors are deleted.  This function implements the ABI notion of
+   non-trivial copy, which has diverged from the one in the standard.  */
+
+bool
+type_has_nontrivial_copy_init (const_tree type)
+{
+  return false;
+}
+
+// forked from gcc/cp/tree.cc build_local_temp
+
+/* Return an undeclared local temporary of type TYPE for use in building a
+   TARGET_EXPR.  */
+
+tree
+build_local_temp (tree type)
+{
+  tree slot = build_decl (input_location, VAR_DECL, NULL_TREE, type);
+  DECL_ARTIFICIAL (slot) = 1;
+  DECL_IGNORED_P (slot) = 1;
+  DECL_CONTEXT (slot) = current_function_decl;
+  layout_decl (slot, 0);
+  return slot;
+}
+
+// forked from gcc/cp/lambda.cc is_normal_capture_proxy
+
+/* Returns true iff DECL is a capture proxy for a normal capture
+   (i.e. without explicit initializer).  */
+
+bool
+is_normal_capture_proxy (tree decl)
+{
+  return false;
+}
+
+// forked from gcc/cp/c-common.cc reject_gcc_builtin
+
+/* For an EXPR of a FUNCTION_TYPE that references a GCC built-in function
+   with no library fallback or for an ADDR_EXPR whose operand is such type
+   issues an error pointing to the location LOC.
+   Returns true when the expression has been diagnosed and false
+   otherwise.  */
+
+bool
+reject_gcc_builtin (const_tree expr, location_t loc /* = UNKNOWN_LOCATION */)
+{
+  if (TREE_CODE (expr) == ADDR_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
+  if (TREE_TYPE (expr) && TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
+      && TREE_CODE (expr) == FUNCTION_DECL
+      /* The intersection of DECL_BUILT_IN and DECL_IS_UNDECLARED_BUILTIN avoids
+	 false positives for user-declared built-ins such as abs or
+	 strlen, and for C++ operators new and delete.
+	 The c_decl_implicit() test avoids false positives for implicitly
+	 declared built-ins with library fallbacks (such as abs).  */
+      && fndecl_built_in_p (expr) && DECL_IS_UNDECLARED_BUILTIN (expr)
+      && !DECL_ASSEMBLER_NAME_SET_P (expr))
+    {
+      if (loc == UNKNOWN_LOCATION)
+	loc = EXPR_LOC_OR_LOC (expr, input_location);
+
+      /* Reject arguments that are built-in functions with
+	 no library fallback.  */
+      error_at (loc, "built-in function %qE must be directly called", expr);
+
+      return true;
+    }
+
+  return false;
+}
+
+// forked from gcc/cp/typeck.cc is_bitfield_expr_with_lowered_type
+
+/* If EXP is a reference to a bit-field, and the type of EXP does not
+   match the declared type of the bit-field, return the declared type
+   of the bit-field.  Otherwise, return NULL_TREE.  */
+
+tree
+is_bitfield_expr_with_lowered_type (const_tree exp)
+{
+  switch (TREE_CODE (exp))
+    {
+    case COND_EXPR:
+      if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)
+						 ? TREE_OPERAND (exp, 1)
+						 : TREE_OPERAND (exp, 0)))
+	return NULL_TREE;
+      return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2));
+
+    case COMPOUND_EXPR:
+      return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1));
+
+    case MODIFY_EXPR:
+    case SAVE_EXPR:
+    case UNARY_PLUS_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case NEGATE_EXPR:
+    case NON_LVALUE_EXPR:
+    case BIT_NOT_EXPR:
+      return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+
+      case COMPONENT_REF: {
+	tree field;
+
+	field = TREE_OPERAND (exp, 1);
+	if (TREE_CODE (field) != FIELD_DECL || !DECL_BIT_FIELD_TYPE (field))
+	  return NULL_TREE;
+	if (same_type_ignoring_top_level_qualifiers_p (
+	      TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
+	  return NULL_TREE;
+	return DECL_BIT_FIELD_TYPE (field);
+      }
+
+    case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (exp))
+	return is_bitfield_expr_with_lowered_type (
+	  DECL_VALUE_EXPR (CONST_CAST_TREE (exp)));
+      return NULL_TREE;
+
+    case VIEW_CONVERT_EXPR:
+      if (location_wrapper_p (exp))
+	return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+      else
+	return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+// forked from gcc/cp/semantics.cc maybe_undo_parenthesized_ref
+
+/* If T is an id-expression obfuscated by force_paren_expr, undo the
+   obfuscation and return the underlying id-expression.  Otherwise
+   return T.  */
+
+tree
+maybe_undo_parenthesized_ref (tree t)
+{
+  if ((TREE_CODE (t) == PAREN_EXPR || TREE_CODE (t) == VIEW_CONVERT_EXPR)
+      && REF_PARENTHESIZED_P (t))
+    t = TREE_OPERAND (t, 0);
+
+  return t;
+}
+
+// forked from gcc/c-family/c-common.cc fold_offsetof
+
+/* Fold an offsetof-like expression.  EXPR is a nested sequence of component
+   references with an INDIRECT_REF of a constant at the bottom; much like the
+   traditional rendering of offsetof as a macro.  TYPE is the desired type of
+   the whole expression.  Return the folded result.  */
+
+tree
+fold_offsetof (tree expr, tree type, enum tree_code ctx)
+{
+  tree base, off, t;
+  tree_code code = TREE_CODE (expr);
+  switch (code)
+    {
+    case ERROR_MARK:
+      return expr;
+
+    case VAR_DECL:
+      error ("cannot apply %<offsetof%> to static data member %qD", expr);
+      return error_mark_node;
+
+    case CALL_EXPR:
+    case TARGET_EXPR:
+      error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
+      return error_mark_node;
+
+    case NOP_EXPR:
+    case INDIRECT_REF:
+      if (!TREE_CONSTANT (TREE_OPERAND (expr, 0)))
+	{
+	  error ("cannot apply %<offsetof%> to a non constant address");
+	  return error_mark_node;
+	}
+      return convert (type, TREE_OPERAND (expr, 0));
+
+    case COMPONENT_REF:
+      base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
+      if (base == error_mark_node)
+	return base;
+
+      t = TREE_OPERAND (expr, 1);
+      if (DECL_C_BIT_FIELD (t))
+	{
+	  error ("attempt to take address of bit-field structure "
+		 "member %qD",
+		 t);
+	  return error_mark_node;
+	}
+      off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t),
+			    size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
+				      / BITS_PER_UNIT));
+      break;
+
+    case ARRAY_REF:
+      base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
+      if (base == error_mark_node)
+	return base;
+
+      t = TREE_OPERAND (expr, 1);
+      STRIP_ANY_LOCATION_WRAPPER (t);
+
+      /* Check if the offset goes beyond the upper bound of the array.  */
+      if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) >= 0)
+	{
+	  tree upbound = array_ref_up_bound (expr);
+	  if (upbound != NULL_TREE && TREE_CODE (upbound) == INTEGER_CST
+	      && !tree_int_cst_equal (upbound,
+				      TYPE_MAX_VALUE (TREE_TYPE (upbound))))
+	    {
+	      if (ctx != ARRAY_REF && ctx != COMPONENT_REF)
+		upbound = size_binop (PLUS_EXPR, upbound,
+				      build_int_cst (TREE_TYPE (upbound), 1));
+	      if (tree_int_cst_lt (upbound, t))
+		{
+		  tree v;
+
+		  for (v = TREE_OPERAND (expr, 0);
+		       TREE_CODE (v) == COMPONENT_REF; v = TREE_OPERAND (v, 0))
+		    if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+			== RECORD_TYPE)
+		      {
+			tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
+			for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
+			  if (TREE_CODE (fld_chain) == FIELD_DECL)
+			    break;
+
+			if (fld_chain)
+			  break;
+		      }
+		  /* Don't warn if the array might be considered a poor
+		     man's flexible array member with a very permissive
+		     definition thereof.  */
+		  if (TREE_CODE (v) == ARRAY_REF
+		      || TREE_CODE (v) == COMPONENT_REF)
+		    warning (OPT_Warray_bounds,
+			     "index %E denotes an offset "
+			     "greater than size of %qT",
+			     t, TREE_TYPE (TREE_OPERAND (expr, 0)));
+		}
+	    }
+	}
+
+      t = convert (sizetype, t);
+      off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+      break;
+
+    case COMPOUND_EXPR:
+      /* Handle static members of volatile structs.  */
+      t = TREE_OPERAND (expr, 1);
+      gcc_checking_assert (VAR_P (get_base_address (t)));
+      return fold_offsetof (t, type);
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (!POINTER_TYPE_P (type))
+    return size_binop (PLUS_EXPR, base, convert (type, off));
+  return fold_build_pointer_plus (base, off);
+}
+
+// forked from gcc/cp/tree.cc char_type_p
+
+/* Returns nonzero if TYPE is a character type, including wchar_t.  */
+
+int
+char_type_p (tree type)
+{
+  return (same_type_p (type, char_type_node)
+	  || same_type_p (type, unsigned_char_type_node)
+	  || same_type_p (type, signed_char_type_node)
+	  || same_type_p (type, char8_type_node)
+	  || same_type_p (type, char16_type_node)
+	  || same_type_p (type, char32_type_node)
+	  || same_type_p (type, wchar_type_node));
+}
+
+// forked from gcc/cp/pt.cc resolve_nondeduced_context
+
+/* Core DR 115: In contexts where deduction is done and fails, or in
+   contexts where deduction is not done, if a template argument list is
+   specified and it, along with any default template arguments, identifies
+   a single function template specialization, then the template-id is an
+   lvalue for the function template specialization.  */
+
+tree
+resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain)
+{
+  tree expr, offset, baselink;
+  bool addr;
+
+  if (!type_unknown_p (orig_expr))
+    return orig_expr;
+
+  expr = orig_expr;
+  addr = false;
+  offset = NULL_TREE;
+  baselink = NULL_TREE;
+
+  if (TREE_CODE (expr) == ADDR_EXPR)
+    {
+      expr = TREE_OPERAND (expr, 0);
+      addr = true;
+    }
+
+  return orig_expr;
+}
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index b93e9364990..9e8de7cf833 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -158,6 +158,89 @@
 #define VAR_OR_FUNCTION_DECL_CHECK(NODE)                                       \
   TREE_CHECK2 (NODE, VAR_DECL, FUNCTION_DECL)
 
+// forked from gcc/cp/c-common.h c_tree_index
+
+/* Standard named or nameless data types of the C compiler.  */
+
+enum c_tree_index
+{
+  CTI_CHAR8_TYPE,
+  CTI_CHAR16_TYPE,
+  CTI_CHAR32_TYPE,
+  CTI_WCHAR_TYPE,
+  CTI_UNDERLYING_WCHAR_TYPE,
+  CTI_WINT_TYPE,
+  CTI_SIGNED_SIZE_TYPE,	     /* For format checking only.  */
+  CTI_UNSIGNED_PTRDIFF_TYPE, /* For format checking only.  */
+  CTI_INTMAX_TYPE,
+  CTI_UINTMAX_TYPE,
+  CTI_WIDEST_INT_LIT_TYPE,
+  CTI_WIDEST_UINT_LIT_TYPE,
+
+  /* Types for <stdint.h>, that may not be defined on all
+     targets.  */
+  CTI_SIG_ATOMIC_TYPE,
+  CTI_INT8_TYPE,
+  CTI_INT16_TYPE,
+  CTI_INT32_TYPE,
+  CTI_INT64_TYPE,
+  CTI_UINT8_TYPE,
+  CTI_UINT16_TYPE,
+  CTI_UINT32_TYPE,
+  CTI_UINT64_TYPE,
+  CTI_INT_LEAST8_TYPE,
+  CTI_INT_LEAST16_TYPE,
+  CTI_INT_LEAST32_TYPE,
+  CTI_INT_LEAST64_TYPE,
+  CTI_UINT_LEAST8_TYPE,
+  CTI_UINT_LEAST16_TYPE,
+  CTI_UINT_LEAST32_TYPE,
+  CTI_UINT_LEAST64_TYPE,
+  CTI_INT_FAST8_TYPE,
+  CTI_INT_FAST16_TYPE,
+  CTI_INT_FAST32_TYPE,
+  CTI_INT_FAST64_TYPE,
+  CTI_UINT_FAST8_TYPE,
+  CTI_UINT_FAST16_TYPE,
+  CTI_UINT_FAST32_TYPE,
+  CTI_UINT_FAST64_TYPE,
+  CTI_INTPTR_TYPE,
+  CTI_UINTPTR_TYPE,
+
+  CTI_CHAR_ARRAY_TYPE,
+  CTI_CHAR8_ARRAY_TYPE,
+  CTI_CHAR16_ARRAY_TYPE,
+  CTI_CHAR32_ARRAY_TYPE,
+  CTI_WCHAR_ARRAY_TYPE,
+  CTI_STRING_TYPE,
+  CTI_CONST_STRING_TYPE,
+
+  /* Type for boolean expressions (bool in C++, int in C).  */
+  CTI_TRUTHVALUE_TYPE,
+  CTI_TRUTHVALUE_TRUE,
+  CTI_TRUTHVALUE_FALSE,
+
+  CTI_DEFAULT_FUNCTION_TYPE,
+
+  CTI_NULL,
+
+  /* These are not types, but we have to look them up all the time.  */
+  CTI_FUNCTION_NAME_DECL,
+  CTI_PRETTY_FUNCTION_NAME_DECL,
+  CTI_C99_FUNCTION_NAME_DECL,
+
+  CTI_MODULE_HWM,
+  /* Below here entities change during compilation.  */
+
+  CTI_SAVED_FUNCTION_NAME_DECLS,
+
+  CTI_MAX
+};
+
+// forked from gcc/c-family/c-common.h c_tree_index
+
+extern GTY (()) tree c_global_trees[CTI_MAX];
+
 // forked from gcc/cp/cp-tree.h cp_tree_index
 
 enum cp_tree_index
@@ -307,6 +390,71 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 /* std::align_val_t */
 #define align_type_node cp_global_trees[CPTI_ALIGN_TYPE]
 
+#define char8_type_node c_global_trees[CTI_CHAR8_TYPE]
+#define char16_type_node c_global_trees[CTI_CHAR16_TYPE]
+#define char32_type_node c_global_trees[CTI_CHAR32_TYPE]
+#define wchar_type_node c_global_trees[CTI_WCHAR_TYPE]
+#define underlying_wchar_type_node c_global_trees[CTI_UNDERLYING_WCHAR_TYPE]
+#define wint_type_node c_global_trees[CTI_WINT_TYPE]
+#define signed_size_type_node c_global_trees[CTI_SIGNED_SIZE_TYPE]
+#define unsigned_ptrdiff_type_node c_global_trees[CTI_UNSIGNED_PTRDIFF_TYPE]
+#define intmax_type_node c_global_trees[CTI_INTMAX_TYPE]
+#define uintmax_type_node c_global_trees[CTI_UINTMAX_TYPE]
+#define widest_integer_literal_type_node c_global_trees[CTI_WIDEST_INT_LIT_TYPE]
+#define widest_unsigned_literal_type_node                                      \
+  c_global_trees[CTI_WIDEST_UINT_LIT_TYPE]
+
+#define sig_atomic_type_node c_global_trees[CTI_SIG_ATOMIC_TYPE]
+#define int8_type_node c_global_trees[CTI_INT8_TYPE]
+#define int16_type_node c_global_trees[CTI_INT16_TYPE]
+#define int32_type_node c_global_trees[CTI_INT32_TYPE]
+#define int64_type_node c_global_trees[CTI_INT64_TYPE]
+#define uint8_type_node c_global_trees[CTI_UINT8_TYPE]
+#define c_uint16_type_node c_global_trees[CTI_UINT16_TYPE]
+#define c_uint32_type_node c_global_trees[CTI_UINT32_TYPE]
+#define c_uint64_type_node c_global_trees[CTI_UINT64_TYPE]
+#define int_least8_type_node c_global_trees[CTI_INT_LEAST8_TYPE]
+#define int_least16_type_node c_global_trees[CTI_INT_LEAST16_TYPE]
+#define int_least32_type_node c_global_trees[CTI_INT_LEAST32_TYPE]
+#define int_least64_type_node c_global_trees[CTI_INT_LEAST64_TYPE]
+#define uint_least8_type_node c_global_trees[CTI_UINT_LEAST8_TYPE]
+#define uint_least16_type_node c_global_trees[CTI_UINT_LEAST16_TYPE]
+#define uint_least32_type_node c_global_trees[CTI_UINT_LEAST32_TYPE]
+#define uint_least64_type_node c_global_trees[CTI_UINT_LEAST64_TYPE]
+#define int_fast8_type_node c_global_trees[CTI_INT_FAST8_TYPE]
+#define int_fast16_type_node c_global_trees[CTI_INT_FAST16_TYPE]
+#define int_fast32_type_node c_global_trees[CTI_INT_FAST32_TYPE]
+#define int_fast64_type_node c_global_trees[CTI_INT_FAST64_TYPE]
+#define uint_fast8_type_node c_global_trees[CTI_UINT_FAST8_TYPE]
+#define uint_fast16_type_node c_global_trees[CTI_UINT_FAST16_TYPE]
+#define uint_fast32_type_node c_global_trees[CTI_UINT_FAST32_TYPE]
+#define uint_fast64_type_node c_global_trees[CTI_UINT_FAST64_TYPE]
+#define intptr_type_node c_global_trees[CTI_INTPTR_TYPE]
+#define uintptr_type_node c_global_trees[CTI_UINTPTR_TYPE]
+
+#define truthvalue_type_node c_global_trees[CTI_TRUTHVALUE_TYPE]
+#define truthvalue_true_node c_global_trees[CTI_TRUTHVALUE_TRUE]
+#define truthvalue_false_node c_global_trees[CTI_TRUTHVALUE_FALSE]
+
+#define char_array_type_node c_global_trees[CTI_CHAR_ARRAY_TYPE]
+#define char8_array_type_node c_global_trees[CTI_CHAR8_ARRAY_TYPE]
+#define char16_array_type_node c_global_trees[CTI_CHAR16_ARRAY_TYPE]
+#define char32_array_type_node c_global_trees[CTI_CHAR32_ARRAY_TYPE]
+#define wchar_array_type_node c_global_trees[CTI_WCHAR_ARRAY_TYPE]
+#define string_type_node c_global_trees[CTI_STRING_TYPE]
+#define const_string_type_node c_global_trees[CTI_CONST_STRING_TYPE]
+
+#define default_function_type c_global_trees[CTI_DEFAULT_FUNCTION_TYPE]
+
+#define function_name_decl_node c_global_trees[CTI_FUNCTION_NAME_DECL]
+#define pretty_function_name_decl_node                                         \
+  c_global_trees[CTI_PRETTY_FUNCTION_NAME_DECL]
+#define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL]
+#define saved_function_name_decls c_global_trees[CTI_SAVED_FUNCTION_NAME_DECLS]
+
+/* The node for C++ `__null'.  */
+#define null_node c_global_trees[CTI_NULL]
+
 /* We cache these tree nodes so as to call get_identifier less frequently.
    For identifiers for functions, including special member functions such
    as ctors and assignment operators, the nodes can be used (among other
@@ -911,6 +1059,45 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 /* Nonzero if DECL was declared with '= default' (maybe implicitly).  */
 #define DECL_DEFAULTED_FN(DECL) (LANG_DECL_FN_CHECK (DECL)->defaulted_p)
 
+/* True if NODE is a brace-enclosed initializer.  */
+#define BRACE_ENCLOSED_INITIALIZER_P(NODE)                                     \
+  (TREE_CODE (NODE) == CONSTRUCTOR && TREE_TYPE (NODE) == init_list_type_node)
+
+/* True if FNDECL is an immediate function.  */
+#define DECL_IMMEDIATE_FUNCTION_P(NODE)                                        \
+  (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE))                             \
+     ? LANG_DECL_FN_CHECK (NODE)->immediate_fn_p                               \
+     : false)
+#define SET_DECL_IMMEDIATE_FUNCTION_P(NODE)                                    \
+  (retrofit_lang_decl (FUNCTION_DECL_CHECK (NODE)),                            \
+   LANG_DECL_FN_CHECK (NODE)->immediate_fn_p = true)
+
+/* True if this CONSTRUCTOR should not be used as a variable initializer
+   because it was loaded from a constexpr variable with mutable fields.  */
+#define CONSTRUCTOR_MUTABLE_POISON(NODE)                                       \
+  (TREE_LANG_FLAG_2 (CONSTRUCTOR_CHECK (NODE)))
+
+/* For a pointer-to-member constant `X::Y' this is the _DECL for
+   `Y'.  */
+#define PTRMEM_CST_MEMBER(NODE)                                                \
+  (((ptrmem_cst_t) PTRMEM_CST_CHECK (NODE))->member)
+
+/* Indicates whether a COMPONENT_REF or a SCOPE_REF has been parenthesized, an
+   INDIRECT_REF comes from parenthesizing a _DECL, or a PAREN_EXPR identifies a
+   parenthesized initializer relevant for decltype(auto).  Currently only set
+   some of the time in C++14 mode.  */
+
+#define REF_PARENTHESIZED_P(NODE)                                              \
+  TREE_LANG_FLAG_2 (TREE_CHECK5 ((NODE), COMPONENT_REF, INDIRECT_REF,          \
+				 SCOPE_REF, VIEW_CONVERT_EXPR, PAREN_EXPR))
+
+/* Returns true if NODE is a pointer-to-member.  */
+#define TYPE_PTRMEM_P(NODE)                                                    \
+  (TYPE_PTRDATAMEM_P (NODE) || TYPE_PTRMEMFUNC_P (NODE))
+
+/* Returns true if NODE is a pointer or a pointer-to-member.  */
+#define TYPE_PTR_OR_PTRMEM_P(NODE) (TYPE_PTR_P (NODE) || TYPE_PTRMEM_P (NODE))
+
 #if defined ENABLE_TREE_CHECKING
 
 #define LANG_DECL_MIN_CHECK(NODE)                                              \
@@ -1035,6 +1222,68 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 
 // Above macros are copied from gcc/cp/name-lookup.cc
 
+// forked from gcc/cp/cp-tree.h warning_sentinel
+
+/* RAII sentinel to disable certain warnings during template substitution
+   and elsewhere.  */
+
+class warning_sentinel
+{
+public:
+  int &flag;
+  int val;
+  warning_sentinel (int &flag, bool suppress = true) : flag (flag), val (flag)
+  {
+    if (suppress)
+      flag = 0;
+  }
+  ~warning_sentinel () { flag = val; }
+};
+
+// forked from gcc/cp/cp-tree.h uid_sensitive_constexpr_evaluation_checker
+
+/* Used to determine whether uid_sensitive_constexpr_evaluation_p was
+   called and returned true, indicating that we've restricted constexpr
+   evaluation in order to avoid UID generation.  We use this to control
+   updates to the fold_cache and cv_cache.  */
+
+struct uid_sensitive_constexpr_evaluation_checker
+{
+  const unsigned saved_counter;
+  uid_sensitive_constexpr_evaluation_checker ();
+  bool evaluation_restricted_p () const;
+};
+
+// forked from gcc/cp/cp-tree.h iloc_sentinel
+
+/* RAII sentinel to temporarily override input_location.  This will not set
+   input_location to UNKNOWN_LOCATION or BUILTINS_LOCATION.  */
+
+class iloc_sentinel
+{
+  location_t saved_loc;
+
+public:
+  iloc_sentinel (location_t loc) : saved_loc (input_location)
+  {
+    if (loc >= RESERVED_LOCATION_COUNT)
+      input_location = loc;
+  }
+  ~iloc_sentinel () { input_location = saved_loc; }
+};
+
+// forked from gcc/cp/cp-tree.h ptrmem_cst
+
+struct GTY (()) ptrmem_cst
+{
+  struct tree_common common;
+  tree member;
+  location_t locus;
+};
+typedef struct ptrmem_cst *ptrmem_cst_t;
+
+// forked from gcc/cp/cp-tree.h named_decl_hash
+
 /* hash traits for declarations.  Hashes potential overload sets via
    DECL_NAME.  */
 
@@ -1736,8 +1985,8 @@ mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc,
 // function with no library fallback (or any of its bits, such as in
 // a conversion to bool).
 extern tree
-mark_rvalue_use (tree e, location_t loc /* = UNKNOWN_LOCATION */,
-		 bool reject_builtin /* = true */);
+mark_rvalue_use (tree, location_t = UNKNOWN_LOCATION,
+		 bool reject_builtin = true);
 
 // Called whenever an expression is used in an lvalue context.
 extern tree
@@ -1901,6 +2150,50 @@ extern bool reduced_constant_expression_p (tree);
 
 extern tree cv_unqualified (tree);
 
+extern tree cp_get_callee (tree);
+extern tree cp_get_callee_fndecl_nofold (tree);
+
+extern bool is_nondependent_static_init_expression (tree);
+
+extern tree
+maybe_constant_init (tree, tree = NULL_TREE, bool = false);
+
+extern tree build_nop (tree, tree);
+
+extern bool scalarish_type_p (const_tree);
+
+extern tree is_bitfield_expr_with_lowered_type (const_tree);
+
+extern tree convert_bitfield_to_declared_type (tree);
+
+extern tree
+cp_fold_maybe_rvalue (tree, bool);
+
+extern tree maybe_undo_parenthesized_ref (tree);
+
+extern tree
+fold_offsetof (tree, tree = size_type_node, tree_code ctx = ERROR_MARK);
+
+extern tree cp_truthvalue_conversion (tree, tsubst_flags_t);
+
+extern tree
+fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error,
+			 bool = false, tree = NULL_TREE);
+
+extern int char_type_p (tree);
+
+extern bool instantiation_dependent_expression_p (tree);
+
+extern bool type_has_nontrivial_copy_init (const_tree);
+
+extern tree build_local_temp (tree);
+
+extern bool is_normal_capture_proxy (tree);
+
+extern bool reject_gcc_builtin (const_tree, location_t = UNKNOWN_LOCATION);
+
+extern tree resolve_nondeduced_context (tree, tsubst_flags_t);
+
 // forked from gcc/cp/cp-tree.h
 
 enum
@@ -2062,6 +2355,13 @@ vec_safe_push (releasing_vec &r, const tree &t CXX_MEM_STAT_INFO)
   return vec_safe_push (*&r, t PASS_MEM_STAT);
 }
 
+inline bool
+null_node_p (const_tree expr)
+{
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+  return expr == null_node;
+}
+
 } // namespace Rust
 
 #endif // RUST_TREE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a5b583d021a4cbbfafecc28445709afe32cdd1c8

commit a5b583d021a4cbbfafecc28445709afe32cdd1c8
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Mon Jul 11 15:59:56 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - next_initializable_field
     - sufficient_parms_p
     - default_ctor_p
     - user_provided_p
     - type_has_non_user_provided_default_constructor
     - default_init_uninitialized_part
     - extract_conversion_operator
     - get_class_binding_direct
     - lang_check_failed
     - skip_artificial_parms_for
     - in_class_defaulted_default_constructor
     - is_instantiation_of_constexpr
     - check_for_uninitialized_const_var
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 362 ++++++++++++++++++++++++++++++++++++++++--
 gcc/rust/backend/rust-tree.h  | 161 ++++++++++++++++++-
 2 files changed, 506 insertions(+), 17 deletions(-)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 4439dea251e..52dae395973 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -23,6 +23,9 @@
 #include "escaped_string.h"
 #include "libiberty.h"
 #include "stor-layout.h"
+#include "hash-map.h"
+#include "diagnostic.h"
+#include "timevar.h"
 
 namespace Rust {
 
@@ -1134,9 +1137,7 @@ ovl_make (tree fn, tree next)
   if (TREE_CODE (fn) == OVERLOAD)
     OVL_NESTED_P (result) = true;
 
-  TREE_TYPE (result)
-    = (next || TREE_CODE (fn) == TEMPLATE_DECL ? unknown_type_node
-					       : TREE_TYPE (fn));
+  TREE_TYPE (result) = (next ? unknown_type_node : TREE_TYPE (fn));
   if (next && TREE_CODE (next) == OVERLOAD && OVL_DEDUP_P (next))
     OVL_DEDUP_P (result) = true;
   OVL_FUNCTION (result) = fn;
@@ -1154,13 +1155,7 @@ lookup_add (tree fns, tree lookup)
   if (fns == error_mark_node || lookup == error_mark_node)
     return error_mark_node;
 
-  if (lookup || TREE_CODE (fns) == TEMPLATE_DECL)
-    {
-      lookup = ovl_make (fns, lookup);
-      OVL_LOOKUP_P (lookup) = true;
-    }
-  else
-    lookup = fns;
+  lookup = fns;
 
   return lookup;
 }
@@ -1655,10 +1650,6 @@ called_fns_equal (tree t1, tree t2)
 	      != DECL_CONTEXT (get_first_fn (t2))))
 	return false;
 
-      if (TREE_CODE (t1) == TEMPLATE_ID_EXPR)
-	targs1 = TREE_OPERAND (t1, 1);
-      if (TREE_CODE (t2) == TEMPLATE_ID_EXPR)
-	targs2 = TREE_OPERAND (t2, 1);
       return rs_tree_equal (targs1, targs2);
     }
   else
@@ -2421,7 +2412,6 @@ rs_build_qualified_type_real (tree type, int type_quals,
   /* A restrict-qualified type must be a pointer (or reference)
      to object or incomplete type. */
   if ((type_quals & TYPE_QUAL_RESTRICT)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
       && TREE_CODE (type) != TYPENAME_TYPE && !INDIRECT_TYPE_P (type))
     {
       bad_quals |= TYPE_QUAL_RESTRICT;
@@ -2822,4 +2812,346 @@ comptypes (tree t1, tree t2, int strict)
     return structural_comptypes (t1, t2, strict);
 }
 
+// forked from gcc/cp/decl.cc next_initializable_field
+
+/* FIELD is an element of TYPE_FIELDS or NULL.  In the former case, the value
+   returned is the next FIELD_DECL (possibly FIELD itself) that can be
+   initialized.  If there are no more such fields, the return value
+   will be NULL.  */
+
+tree
+next_initializable_field (tree field)
+{
+  while (field
+	 && (TREE_CODE (field) != FIELD_DECL || DECL_UNNAMED_BIT_FIELD (field)
+	     || (DECL_ARTIFICIAL (field)
+		 /* Don't skip vptr fields.  We might see them when we're
+		    called from reduced_constant_expression_p.  */
+		 && !DECL_VIRTUAL_P (field))))
+    field = DECL_CHAIN (field);
+
+  return field;
+}
+
+// forked from gcc/cp/call.cc sufficient_parms_p
+
+/* Returns nonzero if PARMLIST consists of only default parms,
+   ellipsis, and/or undeduced parameter packs.  */
+
+bool
+sufficient_parms_p (const_tree parmlist)
+{
+  for (; parmlist && parmlist != void_list_node;
+       parmlist = TREE_CHAIN (parmlist))
+    if (!TREE_PURPOSE (parmlist))
+      return false;
+  return true;
+}
+
+// forked from gcc/cp/class.cc default_ctor_p
+
+/* Returns true if FN is a default constructor.  */
+
+bool
+default_ctor_p (const_tree fn)
+{
+  return (DECL_CONSTRUCTOR_P (fn)
+	  && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)));
+}
+
+// forked from gcc/cp/class.cc user_provided_p
+
+/* Returns true iff FN is a user-provided function, i.e. user-declared
+   and not defaulted at its first declaration.  */
+
+bool
+user_provided_p (tree fn)
+{
+  return (!DECL_ARTIFICIAL (fn)
+	  && !(DECL_INITIALIZED_IN_CLASS_P (fn)
+	       && (DECL_DEFAULTED_FN (fn) || DECL_DELETED_FN (fn))));
+}
+
+// forked from gcc/cp/class.cc type_has_non_user_provided_default_constructor
+
+/* Returns true iff class T has a non-user-provided (i.e. implicitly
+   declared or explicitly defaulted in the class body) default
+   constructor.  */
+
+bool
+type_has_non_user_provided_default_constructor (tree t)
+{
+  if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (t))
+    return false;
+  if (CLASSTYPE_LAZY_DEFAULT_CTOR (t))
+    return true;
+
+  for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+    {
+      tree fn = *iter;
+      if (TREE_CODE (fn) == FUNCTION_DECL && default_ctor_p (fn)
+	  && !user_provided_p (fn))
+	return true;
+    }
+
+  return false;
+}
+
+// forked from gcc/cp/class.cc default_init_uninitialized_part
+
+/* If default-initialization leaves part of TYPE uninitialized, returns
+   a DECL for the field or TYPE itself (DR 253).  */
+
+tree
+default_init_uninitialized_part (tree type)
+{
+  tree t, r, binfo;
+  int i;
+
+  type = strip_array_types (type);
+  if (!CLASS_TYPE_P (type))
+    return type;
+  if (!type_has_non_user_provided_default_constructor (type))
+    return NULL_TREE;
+  for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i)
+    {
+      r = default_init_uninitialized_part (BINFO_TYPE (t));
+      if (r)
+	return r;
+    }
+  for (t = next_initializable_field (TYPE_FIELDS (type)); t;
+       t = next_initializable_field (DECL_CHAIN (t)))
+    if (!DECL_INITIAL (t) && !DECL_ARTIFICIAL (t))
+      {
+	r = default_init_uninitialized_part (TREE_TYPE (t));
+	if (r)
+	  return DECL_P (r) ? r : t;
+      }
+
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/name-lookup.cc extract_conversion_operator
+
+/* FNS is an overload set of conversion functions.  Return the
+   overloads converting to TYPE.  */
+
+static tree
+extract_conversion_operator (tree fns, tree type)
+{
+  tree convs = NULL_TREE;
+  tree tpls = NULL_TREE;
+
+  for (ovl_iterator iter (fns); iter; ++iter)
+    {
+      if (same_type_p (DECL_CONV_FN_TYPE (*iter), type))
+	convs = lookup_add (*iter, convs);
+    }
+
+  if (!convs)
+    convs = tpls;
+
+  return convs;
+}
+
+// forked from gcc/cp/name-lookup.cc
+
+/* Look for NAME as an immediate member of KLASS (including
+   anon-members or unscoped enum member).  TYPE_OR_FNS is zero for
+   regular search.  >0 to get a type binding (if there is one) and <0
+   if you want (just) the member function binding.
+
+   Use this if you do not want lazy member creation.  */
+
+tree
+get_class_binding_direct (tree klass, tree name, bool want_type)
+{
+  gcc_checking_assert (RECORD_OR_UNION_TYPE_P (klass));
+
+  /* Conversion operators can only be found by the marker conversion
+     operator name.  */
+  bool conv_op = IDENTIFIER_CONV_OP_P (name);
+  tree lookup = conv_op ? conv_op_identifier : name;
+  tree val = NULL_TREE;
+  vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass);
+
+  if (COMPLETE_TYPE_P (klass) && member_vec)
+    {
+      val = member_vec_binary_search (member_vec, lookup);
+      if (!val)
+	;
+      else if (STAT_HACK_P (val))
+	val = want_type ? STAT_TYPE (val) : STAT_DECL (val);
+      else if (want_type && !DECL_DECLARES_TYPE_P (val))
+	val = NULL_TREE;
+    }
+  else
+    {
+      if (member_vec && !want_type)
+	val = member_vec_linear_search (member_vec, lookup);
+
+      if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
+	/* Dependent using declarations are a 'field', make sure we
+	   return that even if we saw an overload already.  */
+	if (tree field_val = fields_linear_search (klass, lookup, want_type))
+	  {
+	    if (!val)
+	      val = field_val;
+	    else if (TREE_CODE (field_val) == USING_DECL)
+	      val = ovl_make (field_val, val);
+	  }
+    }
+
+  /* Extract the conversion operators asked for, unless the general
+     conversion operator was requested.   */
+  if (val && conv_op)
+    {
+      gcc_checking_assert (OVL_FUNCTION (val) == conv_op_marker);
+      val = OVL_CHAIN (val);
+      if (tree type = TREE_TYPE (name))
+	val = extract_conversion_operator (val, type);
+    }
+
+  return val;
+}
+
+#if defined ENABLE_TREE_CHECKING
+
+// forked from gcc/cp/tree.cc lang_check_failed
+
+/* Complain that some language-specific thing hanging off a tree
+   node has been accessed improperly.  */
+
+void
+lang_check_failed (const char *file, int line, const char *function)
+{
+  internal_error ("%<lang_*%> check: failed in %s, at %s:%d", function,
+		  trim_filename (file), line);
+}
+#endif /* ENABLE_TREE_CHECKING */
+
+// forked from gcc/cp/tree.cc skip_artificial_parms_for
+
+/* Given a FUNCTION_DECL FN and a chain LIST, skip as many elements of LIST
+   as there are artificial parms in FN.  */
+
+tree
+skip_artificial_parms_for (const_tree fn, tree list)
+{
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+    list = TREE_CHAIN (list);
+  else
+    return list;
+
+  if (DECL_HAS_IN_CHARGE_PARM_P (fn))
+    list = TREE_CHAIN (list);
+  if (DECL_HAS_VTT_PARM_P (fn))
+    list = TREE_CHAIN (list);
+  return list;
+}
+
+// forked from gcc/cp/class.cc in_class_defaulted_default_constructor
+
+/* Returns the defaulted constructor if T has one. Otherwise, returns
+   NULL_TREE.  */
+
+tree
+in_class_defaulted_default_constructor (tree t)
+{
+  if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+    return NULL_TREE;
+
+  for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+    {
+      tree fn = *iter;
+
+      if (DECL_DEFAULTED_IN_CLASS_P (fn) && default_ctor_p (fn))
+	return fn;
+    }
+
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/constexpr.cc
+
+/* Returns true iff FUN is an instantiation of a constexpr function
+   template or a defaulted constexpr function.  */
+
+bool
+is_instantiation_of_constexpr (tree fun)
+{
+  return ((DECL_DEFAULTED_FN (fun) && DECL_DECLARED_CONSTEXPR_P (fun)));
+}
+
+// forked from gcc/cp/decl.cc check_for_uninitialized_const_var
+
+/* Issue an error message if DECL is an uninitialized const variable.
+   CONSTEXPR_CONTEXT_P is true when the function is called in a constexpr
+   context from potential_constant_expression.  Returns true if all is well,
+   false otherwise.  */
+
+bool
+check_for_uninitialized_const_var (tree decl, bool constexpr_context_p,
+				   tsubst_flags_t complain)
+{
+  tree type = strip_array_types (TREE_TYPE (decl));
+
+  /* ``Unless explicitly declared extern, a const object does not have
+     external linkage and must be initialized. ($8.4; $12.1)'' ARM
+     7.1.6 */
+  if (VAR_P (decl) && !TYPE_REF_P (type) && (RS_TYPE_CONST_P (type))
+      && !DECL_NONTRIVIALLY_INITIALIZED_P (decl))
+    {
+      tree field = default_init_uninitialized_part (type);
+      if (!field)
+	return true;
+
+      bool show_notes = true;
+
+      if (!constexpr_context_p)
+	{
+	  if (RS_TYPE_CONST_P (type))
+	    {
+	      if (complain & tf_error)
+		show_notes = permerror (DECL_SOURCE_LOCATION (decl),
+					"uninitialized %<const %D%>", decl);
+	    }
+	  else
+	    {
+	      if (!is_instantiation_of_constexpr (current_function_decl)
+		  && (complain & tf_error))
+		error_at (DECL_SOURCE_LOCATION (decl),
+			  "uninitialized variable %qD in %<constexpr%> "
+			  "function",
+			  decl);
+	      else
+		show_notes = false;
+	    }
+	}
+      else if (complain & tf_error)
+	error_at (DECL_SOURCE_LOCATION (decl),
+		  "uninitialized variable %qD in %<constexpr%> context", decl);
+
+      if (show_notes && CLASS_TYPE_P (type) && (complain & tf_error))
+	{
+	  tree defaulted_ctor;
+
+	  inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
+		  "%q#T has no user-provided default constructor", type);
+	  defaulted_ctor = in_class_defaulted_default_constructor (type);
+	  if (defaulted_ctor)
+	    inform (DECL_SOURCE_LOCATION (defaulted_ctor),
+		    "constructor is not user-provided because it is "
+		    "explicitly defaulted in the class body");
+	  inform (DECL_SOURCE_LOCATION (field),
+		  "and the implicitly-defined constructor does not "
+		  "initialize %q#D",
+		  field);
+	}
+
+      return false;
+    }
+
+  return true;
+}
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index d5cc3186811..b838e402c32 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -763,8 +763,6 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
    level 2.  */
 #define DECL_PARM_LEVEL(NODE) (LANG_DECL_PARM_CHECK (NODE)->level)
 
-#define LANG_DECL_PARM_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.parm)
-
 /* These flags are used by the conversion code.
    CONV_IMPLICIT   :  Perform implicit conversions (standard and user-defined).
    CONV_STATIC     :  Perform the explicit conversions for static_cast.
@@ -845,6 +843,133 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 /* Returns true if NODE is a pointer-to-data-member.  */
 #define TYPE_PTRDATAMEM_P(NODE) (TREE_CODE (NODE) == OFFSET_TYPE)
 
+/* Nonzero if this type is const-qualified.  */
+#define RS_TYPE_CONST_P(NODE) ((rs_type_quals (NODE) & TYPE_QUAL_CONST) != 0)
+
+/* The _DECL for this _TYPE.  */
+#define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
+
+/* Nonzero for a VAR_DECL iff an explicit initializer was provided
+   or a non-trivial constructor is called.  */
+#define DECL_NONTRIVIALLY_INITIALIZED_P(NODE)                                  \
+  (TREE_LANG_FLAG_6 (VAR_DECL_CHECK (NODE)))
+
+/* Nonzero if DECL was declared with '= default' (maybe implicitly).  */
+#define DECL_DEFAULTED_FN(DECL) (LANG_DECL_FN_CHECK (DECL)->defaulted_p)
+
+/* Nonzero for a class type means that the class type has a
+   user-declared constructor.  */
+#define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
+
+/* A FUNCTION_DECL or OVERLOAD for the constructors for NODE.  These
+   are the constructors that take an in-charge parameter.  */
+#define CLASSTYPE_CONSTRUCTORS(NODE)                                           \
+  (get_class_binding_direct (NODE, ctor_identifier))
+
+/* Nonzero if the DECL was initialized in the class definition itself,
+   rather than outside the class.  This is used for both static member
+   VAR_DECLS, and FUNCTION_DECLS that are defined in the class.  */
+#define DECL_INITIALIZED_IN_CLASS_P(DECL)                                      \
+  (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL))                      \
+     ->u.base.initialized_in_class)
+
+/* Nonzero if DECL is explicitly defaulted in the class body.  */
+#define DECL_DEFAULTED_IN_CLASS_P(DECL)                                        \
+  (DECL_DEFAULTED_FN (DECL) && DECL_INITIALIZED_IN_CLASS_P (DECL))
+
+/* Nonzero for FUNCTION_DECL means that this decl is a non-static
+   member function.  */
+#define DECL_NONSTATIC_MEMBER_FUNCTION_P(NODE)                                 \
+  (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+
+/* For FUNCTION_DECLs: nonzero means that this function is a
+   constructor or a destructor with an extra in-charge parameter to
+   control whether or not virtual bases are constructed.  */
+#define DECL_HAS_IN_CHARGE_PARM_P(NODE)                                        \
+  (LANG_DECL_FN_CHECK (NODE)->has_in_charge_parm_p)
+
+/* Nonzero if the VTT parm has been added to NODE.  */
+#define DECL_HAS_VTT_PARM_P(NODE) (LANG_DECL_FN_CHECK (NODE)->has_vtt_parm_p)
+
+/* Given a FUNCTION_DECL, returns the first TREE_LIST out of TYPE_ARG_TYPES
+   which refers to a user-written parameter.  */
+#define FUNCTION_FIRST_USER_PARMTYPE(NODE)                                     \
+  skip_artificial_parms_for ((NODE), TYPE_ARG_TYPES (TREE_TYPE (NODE)))
+
+/* Similarly, but for DECL_ARGUMENTS.  */
+#define FUNCTION_FIRST_USER_PARM(NODE)                                         \
+  skip_artificial_parms_for ((NODE), DECL_ARGUMENTS (NODE))
+
+/* For FUNCTION_DECLs and TEMPLATE_DECLs: nonzero means that this function
+   is a constructor.  */
+#define DECL_CONSTRUCTOR_P(NODE) DECL_CXX_CONSTRUCTOR_P (NODE)
+
+/* Nonzero if DECL was declared with '= delete'.  */
+#define DECL_DELETED_FN(DECL)                                                  \
+  (LANG_DECL_FN_CHECK (DECL)->min.base.threadprivate_or_deleted_p)
+
+/* Nonzero if DECL was declared with '= default' (maybe implicitly).  */
+#define DECL_DEFAULTED_FN(DECL) (LANG_DECL_FN_CHECK (DECL)->defaulted_p)
+
+#if defined ENABLE_TREE_CHECKING
+
+#define LANG_DECL_MIN_CHECK(NODE)                                              \
+  __extension__({                                                              \
+    struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);                          \
+    if (!LANG_DECL_HAS_MIN (NODE))                                             \
+      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);                    \
+    &lt->u.min;                                                                \
+  })
+
+/* We want to be able to check DECL_CONSTRUCTOR_P and such on a function
+   template, not just on a FUNCTION_DECL.  So when looking for things in
+   lang_decl_fn, look down through a TEMPLATE_DECL into its result.  */
+#define LANG_DECL_FN_CHECK(NODE)                                               \
+  __extension__({                                                              \
+    struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);                          \
+    if (!DECL_DECLARES_FUNCTION_P (NODE) || lt->u.base.selector != lds_fn)     \
+      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);                    \
+    &lt->u.fn;                                                                 \
+  })
+
+#define LANG_DECL_NS_CHECK(NODE)                                               \
+  __extension__({                                                              \
+    struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);                          \
+    if (TREE_CODE (NODE) != NAMESPACE_DECL || lt->u.base.selector != lds_ns)   \
+      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);                    \
+    &lt->u.ns;                                                                 \
+  })
+
+#define LANG_DECL_PARM_CHECK(NODE)                                             \
+  __extension__({                                                              \
+    struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);                          \
+    if (TREE_CODE (NODE) != PARM_DECL || lt->u.base.selector != lds_parm)      \
+      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);                    \
+    &lt->u.parm;                                                               \
+  })
+
+#define LANG_DECL_DECOMP_CHECK(NODE)                                           \
+  __extension__({                                                              \
+    struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);                          \
+    if (!VAR_P (NODE) || lt->u.base.selector != lds_decomp)                    \
+      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);                    \
+    &lt->u.decomp;                                                             \
+  })
+
+#else
+
+#define LANG_DECL_MIN_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.min)
+
+#define LANG_DECL_FN_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.fn)
+
+#define LANG_DECL_NS_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.ns)
+
+#define LANG_DECL_PARM_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.parm)
+
+#define LANG_DECL_DECOMP_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.decomp)
+
+#endif /* ENABLE_TREE_CHECKING */
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -1744,6 +1869,38 @@ extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
 
 extern bool comp_ptr_ttypes_const		(tree, tree, compare_bounds_t);
 
+extern tree
+get_class_binding_direct (tree, tree, bool want_type = false);
+
+extern tree skip_artificial_parms_for (const_tree, tree);
+
+extern void
+lang_check_failed (const char *, int,
+		   const char *) ATTRIBUTE_NORETURN ATTRIBUTE_COLD;
+
+extern tree default_init_uninitialized_part (tree);
+
+extern bool type_has_non_user_provided_default_constructor (tree);
+
+extern bool default_ctor_p (const_tree);
+
+extern bool user_provided_p (tree);
+
+extern bool sufficient_parms_p (const_tree);
+
+extern tree next_initializable_field (tree);
+
+extern tree in_class_defaulted_default_constructor (tree);
+
+extern bool is_instantiation_of_constexpr (tree);
+
+extern bool
+check_for_uninitialized_const_var (tree, bool, tsubst_flags_t);
+
+extern bool reduced_constant_expression_p (tree);
+
+extern tree cv_unqualified (tree);
+
 // forked from gcc/cp/cp-tree.h
 
 enum

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3343535fdb7fc36e68949a8642d7e67668b67f6c

commit 3343535fdb7fc36e68949a8642d7e67668b67f6c
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Sun Jul 10 14:42:29 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - fields_linear_search
     - nothrow_spec_p
     - maybe_get_fns
     - get_fns
     - get_first_fn
     - dependent_name
     - called_fns_equal
     - canonical_eh_spec
     - rs_tree_code_length
     - rs_tree_operand_length
     - rs_tree_equal
     - publicly_uniquely_derived_p
     - comp_except_types
     - comp_except_specs
     - compparms
     - rs_build_qualified_type_real
     - vector_targets_convertible_p
     - comp_array_types
     - same_type_ignoring_top_level_qualifiers_p
     - comp_ptr_ttypes_const
     - similar_type_p
     - structural_comptypes
     - comptypes
     - gnu_vector_type_p
     - set_array_type_canon
     - is_byte_access_type
     - build_cplus_array_type
    
    Following structs, classes and enums are ported in this changeset:
     - named_decl_hash
     - lang_decl_selector
     - lang_decl_base
     - lang_decl_min
     - lang_decl_fn
     - lang_decl_ns
     - lang_decl_parm
     - lang_decl_decomp
     - lang_decl
     - lkp_iterator
     - compare_bounds_t
     - cplus_array_info
     - cplus_array_hasher
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 1297 +++++++++++++++++++++++++++++++++++++++++
 gcc/rust/backend/rust-tree.h  |  411 +++++++++++++
 2 files changed, 1708 insertions(+)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 73c50a4cc2c..4439dea251e 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -22,6 +22,7 @@
 #include "attribs.h"
 #include "escaped_string.h"
 #include "libiberty.h"
+#include "stor-layout.h"
 
 namespace Rust {
 
@@ -1525,4 +1526,1300 @@ build_min_array_type (tree elt_type, tree index_type)
   return t;
 }
 
+// forked from gcc/cp/name-lookup.cc fields_linear_search
+
+/* Linear search of (partially ordered) fields of KLASS for NAME.  */
+
+static tree
+fields_linear_search (tree klass, tree name, bool want_type)
+{
+  for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))
+    {
+      tree decl = fields;
+
+      if (DECL_NAME (decl) != name)
+	continue;
+
+      if (DECL_DECLARES_FUNCTION_P (decl))
+	/* Functions are found separately.  */
+	continue;
+
+      if (!want_type || DECL_DECLARES_TYPE_P (decl))
+	return decl;
+    }
+}
+
+// forked from gcc/cp/except.cc canonnothrow_spec_pical_eh_spec
+
+/* Return true iff SPEC is throw() or noexcept(true).  */
+
+bool
+nothrow_spec_p (const_tree spec)
+{
+  if (spec == empty_except_spec || spec == noexcept_true_spec)
+    return true;
+
+  gcc_assert (!spec || TREE_VALUE (spec) || spec == noexcept_false_spec
+	      || TREE_PURPOSE (spec) == error_mark_node);
+
+  return false;
+}
+
+// forked from gcc/cp/tree.cc may_get_fns
+
+/* Get the overload set FROM refers to.  Returns NULL if it's not an
+   overload set.  */
+
+tree
+maybe_get_fns (tree from)
+{
+  STRIP_ANY_LOCATION_WRAPPER (from);
+
+  /* A baselink is also considered an overloaded function.  */
+  if (TREE_CODE (from) == COMPONENT_REF)
+    from = TREE_OPERAND (from, 1);
+
+  if (OVL_P (from))
+    return from;
+
+  return NULL;
+}
+
+// forked from gcc/cp/tree.cc get_fns
+
+/* FROM refers to an overload set.  Return that set (or die).  */
+
+tree
+get_fns (tree from)
+{
+  tree res = maybe_get_fns (from);
+
+  gcc_assert (res);
+  return res;
+}
+
+// forked from gcc/cp/tree.cc get_first_fn
+
+/* Return the first function of the overload set FROM refers to.  */
+
+tree
+get_first_fn (tree from)
+{
+  return OVL_FIRST (get_fns (from));
+}
+
+// forked from gcc/cp/tree.cc dependent_name
+
+/* X is the CALL_EXPR_FN of a CALL_EXPR.  If X represents a dependent name
+   (14.6.2), return the IDENTIFIER_NODE for that name.  Otherwise, return
+   NULL_TREE.  */
+
+tree
+dependent_name (tree x)
+{
+  /* FIXME a dependent name must be unqualified, but this function doesn't
+     distinguish between qualified and unqualified identifiers.  */
+  if (identifier_p (x))
+    return x;
+
+  if (OVL_P (x))
+    return OVL_NAME (x);
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/tree.cc called_fns_equal
+
+/* Subroutine of rs_tree_equal: t1 and t2 are the CALL_EXPR_FNs of two
+   CALL_EXPRS.  Return whether they are equivalent.  */
+
+static bool
+called_fns_equal (tree t1, tree t2)
+{
+  /* Core 1321: dependent names are equivalent even if the overload sets
+     are different.  But do compare explicit template arguments.  */
+  tree name1 = dependent_name (t1);
+  tree name2 = dependent_name (t2);
+  if (name1 || name2)
+    {
+      tree targs1 = NULL_TREE, targs2 = NULL_TREE;
+
+      if (name1 != name2)
+	return false;
+
+      /* FIXME dependent_name currently returns an unqualified name regardless
+	 of whether the function was named with a qualified- or unqualified-id.
+	 Until that's fixed, check that we aren't looking at overload sets from
+	 different scopes.  */
+      if (is_overloaded_fn (t1) && is_overloaded_fn (t2)
+	  && (DECL_CONTEXT (get_first_fn (t1))
+	      != DECL_CONTEXT (get_first_fn (t2))))
+	return false;
+
+      if (TREE_CODE (t1) == TEMPLATE_ID_EXPR)
+	targs1 = TREE_OPERAND (t1, 1);
+      if (TREE_CODE (t2) == TEMPLATE_ID_EXPR)
+	targs2 = TREE_OPERAND (t2, 1);
+      return rs_tree_equal (targs1, targs2);
+    }
+  else
+    return rs_tree_equal (t1, t2);
+}
+
+// forked from gcc/cp/tree.cc canonical_eh_spec
+
+/* Return the canonical version of exception-specification RAISES for a C++17
+   function type, for use in type comparison and building TYPE_CANONICAL.  */
+
+tree
+canonical_eh_spec (tree raises)
+{
+  if (raises == NULL_TREE)
+    return raises;
+  else if (nothrow_spec_p (raises))
+    /* throw() -> noexcept.  */
+    return noexcept_true_spec;
+  else
+    /* For C++17 type matching, anything else -> nothing.  */
+    return NULL_TREE;
+}
+
+/* Like cp_tree_operand_length, but takes a tree_code CODE.  */
+
+int
+rs_tree_code_length (enum tree_code code)
+{
+  gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      return 1;
+
+    case ARRAY_REF:
+      return 2;
+
+    default:
+      return TREE_CODE_LENGTH (code);
+    }
+}
+
+// forked from gcc/cp/tree.cc rs_tree_operand_length
+
+/* Return the number of operands in T that we care about for things like
+   mangling.  */
+
+int
+rs_tree_operand_length (const_tree t)
+{
+  enum tree_code code = TREE_CODE (t);
+
+  if (TREE_CODE_CLASS (code) == tcc_vl_exp)
+    return VL_EXP_OPERAND_LENGTH (t);
+
+  return rs_tree_code_length (code);
+}
+
+// forked from gcc/cp/tree.cc cp_tree_equal
+
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same. Return 0 if they are different.  */
+
+bool
+rs_tree_equal (tree t1, tree t2)
+{
+  enum tree_code code1, code2;
+
+  if (t1 == t2)
+    return true;
+  if (!t1 || !t2)
+    return false;
+
+  code1 = TREE_CODE (t1);
+  code2 = TREE_CODE (t2);
+
+  if (code1 != code2)
+    return false;
+
+  if (CONSTANT_CLASS_P (t1) && !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return false;
+
+  switch (code1)
+    {
+    case VOID_CST:
+      /* There's only a single VOID_CST node, so we should never reach
+	 here.  */
+      gcc_unreachable ();
+
+    case INTEGER_CST:
+      return tree_int_cst_equal (t1, t2);
+
+    case REAL_CST:
+      return real_identical (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2));
+
+    case STRING_CST:
+      return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+	     && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+			 TREE_STRING_LENGTH (t1));
+
+    case FIXED_CST:
+      return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2));
+
+    case COMPLEX_CST:
+      return rs_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
+	     && rs_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+
+    case VECTOR_CST:
+      return operand_equal_p (t1, t2, OEP_ONLY_CONST);
+
+    case CONSTRUCTOR:
+      /* We need to do this when determining whether or not two
+	 non-type pointer to member function template arguments
+	 are the same.  */
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+	  || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
+	return false;
+      {
+	tree field, value;
+	unsigned int i;
+	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
+	  {
+	    constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
+	    if (!rs_tree_equal (field, elt2->index)
+		|| !rs_tree_equal (value, elt2->value))
+	      return false;
+	  }
+      }
+      return true;
+
+    case TREE_LIST:
+      if (!rs_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+	return false;
+      if (!rs_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+	return false;
+      return rs_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+
+    case SAVE_EXPR:
+      return rs_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+      case CALL_EXPR: {
+	if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2))
+	  return false;
+
+	if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+	  return false;
+
+	call_expr_arg_iterator iter1, iter2;
+	init_call_expr_arg_iterator (t1, &iter1);
+	init_call_expr_arg_iterator (t2, &iter2);
+	if (iter1.n != iter2.n)
+	  return false;
+
+	while (more_call_expr_args_p (&iter1))
+	  {
+	    tree arg1 = next_call_expr_arg (&iter1);
+	    tree arg2 = next_call_expr_arg (&iter2);
+
+	    gcc_checking_assert (arg1 && arg2);
+	    if (!rs_tree_equal (arg1, arg2))
+	      return false;
+	  }
+
+	return true;
+      }
+
+      case TARGET_EXPR: {
+	tree o1 = TREE_OPERAND (t1, 0);
+	tree o2 = TREE_OPERAND (t2, 0);
+
+	/* Special case: if either target is an unallocated VAR_DECL,
+	   it means that it's going to be unified with whatever the
+	   TARGET_EXPR is really supposed to initialize, so treat it
+	   as being equivalent to anything.  */
+	if (VAR_P (o1) && DECL_NAME (o1) == NULL_TREE && !DECL_RTL_SET_P (o1))
+	  /*Nop*/;
+	else if (VAR_P (o2) && DECL_NAME (o2) == NULL_TREE
+		 && !DECL_RTL_SET_P (o2))
+	  /*Nop*/;
+	else if (!rs_tree_equal (o1, o2))
+	  return false;
+
+	return rs_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+      }
+
+    case PARM_DECL:
+      /* For comparing uses of parameters in late-specified return types
+	 with an out-of-class definition of the function, but can also come
+	 up for expressions that involve 'this' in a member function
+	 template.  */
+
+      if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	{
+	  if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
+	    return false;
+	  if (CONSTRAINT_VAR_P (t1) ^ CONSTRAINT_VAR_P (t2))
+	    return false;
+	  if (DECL_ARTIFICIAL (t1)
+	      || (DECL_PARM_LEVEL (t1) == DECL_PARM_LEVEL (t2)
+		  && DECL_PARM_INDEX (t1) == DECL_PARM_INDEX (t2)))
+	    return true;
+	}
+      return false;
+
+    case VAR_DECL:
+    case CONST_DECL:
+    case FIELD_DECL:
+    case FUNCTION_DECL:
+    case IDENTIFIER_NODE:
+    case SSA_NAME:
+      return false;
+
+    case TREE_VEC:
+      return true;
+
+    case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
+      /* Used for location wrappers with possibly NULL types.  */
+      if (!TREE_TYPE (t1) || !TREE_TYPE (t2))
+	{
+	  if (TREE_TYPE (t1) || TREE_TYPE (t2))
+	    return false;
+	  break;
+	}
+
+    default:
+      break;
+    }
+
+  switch (TREE_CODE_CLASS (code1))
+    {
+    case tcc_unary:
+    case tcc_binary:
+    case tcc_comparison:
+    case tcc_expression:
+    case tcc_vl_exp:
+    case tcc_reference:
+      case tcc_statement: {
+	int n = rs_tree_operand_length (t1);
+	if (TREE_CODE_CLASS (code1) == tcc_vl_exp
+	    && n != TREE_OPERAND_LENGTH (t2))
+	  return false;
+
+	for (int i = 0; i < n; ++i)
+	  if (!rs_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+	    return false;
+
+	return true;
+      }
+
+    case tcc_type:
+      return same_type_p (t1, t2);
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* We can get here with --disable-checking.  */
+  return false;
+}
+
+// forked from gcc/cp/class.cc publicly_uniquely_derived_p
+
+/* TRUE iff TYPE is publicly & uniquely derived from PARENT.  */
+
+bool
+publicly_uniquely_derived_p (tree parent, tree type)
+{
+  return false;
+}
+
+// forked from gcc/cp/typeck.cc comp_except_types
+
+/* Compare two exception specifier types for exactness or subsetness, if
+   allowed. Returns false for mismatch, true for match (same, or
+   derived and !exact).
+
+   [except.spec] "If a class X ... objects of class X or any class publicly
+   and unambiguously derived from X. Similarly, if a pointer type Y * ...
+   exceptions of type Y * or that are pointers to any type publicly and
+   unambiguously derived from Y. Otherwise a function only allows exceptions
+   that have the same type ..."
+   This does not mention cv qualifiers and is different to what throw
+   [except.throw] and catch [except.catch] will do. They will ignore the
+   top level cv qualifiers, and allow qualifiers in the pointer to class
+   example.
+
+   We implement the letter of the standard.  */
+
+static bool
+comp_except_types (tree a, tree b, bool exact)
+{
+  if (same_type_p (a, b))
+    return true;
+  else if (!exact)
+    {
+      if (rs_type_quals (a) || rs_type_quals (b))
+	return false;
+
+      if (TYPE_PTR_P (a) && TYPE_PTR_P (b))
+	{
+	  a = TREE_TYPE (a);
+	  b = TREE_TYPE (b);
+	  if (rs_type_quals (a) || rs_type_quals (b))
+	    return false;
+	}
+
+      if (TREE_CODE (a) != RECORD_TYPE || TREE_CODE (b) != RECORD_TYPE)
+	return false;
+
+      if (publicly_uniquely_derived_p (a, b))
+	return true;
+    }
+  return false;
+}
+
+// forked from gcc/cp/typeck.cc comp_except_specs
+
+/* Return true if TYPE1 and TYPE2 are equivalent exception specifiers.
+   If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5).
+   If EXACT is ce_type, the C++17 type compatibility rules apply.
+   If EXACT is ce_normal, the compatibility rules in 15.4/3 apply.
+   If EXACT is ce_exact, the specs must be exactly the same. Exception lists
+   are unordered, but we've already filtered out duplicates. Most lists will
+   be in order, we should try to make use of that.  */
+
+bool
+comp_except_specs (const_tree t1, const_tree t2, int exact)
+{
+  const_tree probe;
+  const_tree base;
+  int length = 0;
+
+  if (t1 == t2)
+    return true;
+
+  /* First handle noexcept.  */
+  if (exact < ce_exact)
+    {
+      if (exact == ce_type
+	  && (canonical_eh_spec (CONST_CAST_TREE (t1))
+	      == canonical_eh_spec (CONST_CAST_TREE (t2))))
+	return true;
+
+      /* noexcept(false) is compatible with no exception-specification,
+	 and less strict than any spec.  */
+      if (t1 == noexcept_false_spec)
+	return t2 == NULL_TREE || exact == ce_derived;
+      /* Even a derived noexcept(false) is compatible with no
+	 exception-specification.  */
+      if (t2 == noexcept_false_spec)
+	return t1 == NULL_TREE;
+
+      /* Otherwise, if we aren't looking for an exact match, noexcept is
+	 equivalent to throw().  */
+      if (t1 == noexcept_true_spec)
+	t1 = empty_except_spec;
+      if (t2 == noexcept_true_spec)
+	t2 = empty_except_spec;
+    }
+
+  /* If any noexcept is left, it is only comparable to itself;
+     either we're looking for an exact match or we're redeclaring a
+     template with dependent noexcept.  */
+  if ((t1 && TREE_PURPOSE (t1)) || (t2 && TREE_PURPOSE (t2)))
+    return (t1 && t2 && rs_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)));
+
+  if (t1 == NULL_TREE) /* T1 is ...  */
+    return t2 == NULL_TREE || exact == ce_derived;
+  if (!TREE_VALUE (t1)) /* t1 is EMPTY */
+    return t2 != NULL_TREE && !TREE_VALUE (t2);
+  if (t2 == NULL_TREE) /* T2 is ...  */
+    return false;
+  if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+    return exact == ce_derived;
+
+  /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
+     Count how many we find, to determine exactness. For exact matching and
+     ordered T1, T2, this is an O(n) operation, otherwise its worst case is
+     O(nm).  */
+  for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
+    {
+      for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
+	{
+	  tree a = TREE_VALUE (probe);
+	  tree b = TREE_VALUE (t2);
+
+	  if (comp_except_types (a, b, exact))
+	    {
+	      if (probe == base && exact > ce_derived)
+		base = TREE_CHAIN (probe);
+	      length++;
+	      break;
+	    }
+	}
+      if (probe == NULL_TREE)
+	return false;
+    }
+  return exact == ce_derived || base == NULL_TREE || length == list_length (t1);
+}
+
+// forked from gcc/cp/typeck.cc compparms
+
+/* Subroutines of `comptypes'.  */
+
+/* Return true if two parameter type lists PARMS1 and PARMS2 are
+   equivalent in the sense that functions with those parameter types
+   can have equivalent types.  The two lists must be equivalent,
+   element by element.  */
+
+bool
+compparms (const_tree parms1, const_tree parms2)
+{
+  const_tree t1, t2;
+
+  /* An unspecified parmlist matches any specified parmlist
+     whose argument types don't need default promotions.  */
+
+  for (t1 = parms1, t2 = parms2; t1 || t2;
+       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+    {
+      /* If one parmlist is shorter than the other,
+	 they fail to match.  */
+      if (!t1 || !t2)
+	return false;
+      if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
+	return false;
+    }
+  return true;
+}
+
+/* Set TYPE_CANONICAL like build_array_type_1, but using
+   build_cplus_array_type.  */
+
+static void
+set_array_type_canon (tree t, tree elt_type, tree index_type, bool dep)
+{
+  /* Set the canonical type for this new node.  */
+  if (TYPE_STRUCTURAL_EQUALITY_P (elt_type)
+      || (index_type && TYPE_STRUCTURAL_EQUALITY_P (index_type)))
+    SET_TYPE_STRUCTURAL_EQUALITY (t);
+  else if (TYPE_CANONICAL (elt_type) != elt_type
+	   || (index_type && TYPE_CANONICAL (index_type) != index_type))
+    TYPE_CANONICAL (t)
+      = build_cplus_array_type (TYPE_CANONICAL (elt_type),
+				index_type
+				? TYPE_CANONICAL (index_type) : index_type,
+				dep);
+  else
+    TYPE_CANONICAL (t) = t;
+}
+
+// forked from gcc/cp/tree.cc cplus_array_info
+
+struct cplus_array_info
+{
+  tree type;
+  tree domain;
+};
+
+// forked from gcc/cp/tree.cc cplus_array_hasher
+
+struct cplus_array_hasher : ggc_ptr_hash<tree_node>
+{
+  typedef cplus_array_info *compare_type;
+
+  static hashval_t hash (tree t);
+  static bool equal (tree, cplus_array_info *);
+};
+
+/* Hash an ARRAY_TYPE.  K is really of type `tree'.  */
+
+hashval_t
+cplus_array_hasher::hash (tree t)
+{
+  hashval_t hash;
+
+  hash = TYPE_UID (TREE_TYPE (t));
+  if (TYPE_DOMAIN (t))
+    hash ^= TYPE_UID (TYPE_DOMAIN (t));
+  return hash;
+}
+
+/* Compare two ARRAY_TYPEs.  K1 is really of type `tree', K2 is really
+   of type `cplus_array_info*'. */
+
+bool
+cplus_array_hasher::equal (tree t1, cplus_array_info *t2)
+{
+  return (TREE_TYPE (t1) == t2->type && TYPE_DOMAIN (t1) == t2->domain);
+}
+
+// forked from gcc/cp/tree.cc cplus_array_htab
+
+/* Hash table containing dependent array types, which are unsuitable for
+   the language-independent type hash table.  */
+static GTY (()) hash_table<cplus_array_hasher> *cplus_array_htab;
+
+// forked from gcc/cp/tree.cc is_byte_access_type
+
+/* Returns true if TYPE is char, unsigned char, or std::byte.  */
+
+bool
+is_byte_access_type (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  if (type == char_type_node
+      || type == unsigned_char_type_node)
+    return true;
+
+  return (TREE_CODE (type) == ENUMERAL_TYPE
+	  && TYPE_CONTEXT (type) == std_node
+	  && !strcmp ("byte", TYPE_NAME_STRING (type)));
+}
+
+// forked from gcc/cp/tree.cc build_cplus_array_type
+
+/* Like build_array_type, but handle special C++ semantics: an array of a
+   variant element type is a variant of the array of the main variant of
+   the element type.  IS_DEPENDENT is -ve if we should determine the
+   dependency.  Otherwise its bool value indicates dependency.  */
+
+tree
+build_cplus_array_type (tree elt_type, tree index_type, int dependent)
+{
+  tree t;
+
+  if (elt_type == error_mark_node || index_type == error_mark_node)
+    return error_mark_node;
+
+  if (dependent < 0)
+    dependent = 0;
+
+  if (elt_type != TYPE_MAIN_VARIANT (elt_type))
+    /* Start with an array of the TYPE_MAIN_VARIANT.  */
+    t = build_cplus_array_type (TYPE_MAIN_VARIANT (elt_type),
+				index_type, dependent);
+  else if (dependent)
+    {
+      /* Since type_hash_canon calls layout_type, we need to use our own
+	 hash table.  */
+      cplus_array_info cai;
+      hashval_t hash;
+
+      if (cplus_array_htab == NULL)
+	cplus_array_htab = hash_table<cplus_array_hasher>::create_ggc (61);
+      
+      hash = TYPE_UID (elt_type);
+      if (index_type)
+	hash ^= TYPE_UID (index_type);
+      cai.type = elt_type;
+      cai.domain = index_type;
+
+      tree *e = cplus_array_htab->find_slot_with_hash (&cai, hash, INSERT); 
+      if (*e)
+	/* We have found the type: we're done.  */
+	return (tree) *e;
+      else
+	{
+	  /* Build a new array type.  */
+	  t = build_min_array_type (elt_type, index_type);
+
+	  /* Store it in the hash table. */
+	  *e = t;
+
+	  /* Set the canonical type for this new node.  */
+	  set_array_type_canon (t, elt_type, index_type, dependent);
+
+	  /* Mark it as dependent now, this saves time later.  */
+	  TYPE_DEPENDENT_P_VALID (t) = true;
+	  TYPE_DEPENDENT_P (t) = true;
+	}
+    }
+  else
+    {
+      bool typeless_storage = is_byte_access_type (elt_type);
+      t = build_array_type (elt_type, index_type, typeless_storage);
+
+      /* Mark as non-dependenty now, this will save time later.  */
+      TYPE_DEPENDENT_P_VALID (t) = true;
+    }
+
+  /* Now check whether we already have this array variant.  */
+  if (elt_type != TYPE_MAIN_VARIANT (elt_type))
+    {
+      tree m = t;
+      for (t = m; t; t = TYPE_NEXT_VARIANT (t))
+	if (TREE_TYPE (t) == elt_type
+	    && TYPE_NAME (t) == NULL_TREE
+	    && TYPE_ATTRIBUTES (t) == NULL_TREE)
+	  break;
+      if (!t)
+	{
+	  t = build_min_array_type (elt_type, index_type);
+	  /* Mark dependency now, this saves time later.  */
+	  TYPE_DEPENDENT_P_VALID (t) = true;
+	  TYPE_DEPENDENT_P (t) = dependent;
+	  set_array_type_canon (t, elt_type, index_type, dependent);
+	  if (!dependent)
+	    {
+	      layout_type (t);
+	      /* Make sure sizes are shared with the main variant.
+		 layout_type can't be called after setting TYPE_NEXT_VARIANT,
+		 as it will overwrite alignment etc. of all variants.  */
+	      TYPE_SIZE (t) = TYPE_SIZE (m);
+	      TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (m);
+	      TYPE_TYPELESS_STORAGE (t) = TYPE_TYPELESS_STORAGE (m);
+	    }
+
+	  TYPE_MAIN_VARIANT (t) = m;
+	  TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
+	  TYPE_NEXT_VARIANT (m) = t;
+	}
+    }
+
+  /* Avoid spurious warnings with VLAs (c++/54583).  */
+  if (TYPE_SIZE (t) && EXPR_P (TYPE_SIZE (t)))
+    suppress_warning (TYPE_SIZE (t), OPT_Wunused);
+
+  /* Push these needs up to the ARRAY_TYPE so that initialization takes
+     place more easily.  */
+  bool needs_ctor = (TYPE_NEEDS_CONSTRUCTING (t)
+		     = TYPE_NEEDS_CONSTRUCTING (elt_type));
+  bool needs_dtor = (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+		     = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type));
+
+  if (!dependent && t == TYPE_MAIN_VARIANT (t)
+      && !COMPLETE_TYPE_P (t) && COMPLETE_TYPE_P (elt_type))
+    {
+      /* The element type has been completed since the last time we saw
+	 this array type; update the layout and 'tor flags for any variants
+	 that need it.  */
+      layout_type (t);
+      for (tree v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
+	{
+	  TYPE_NEEDS_CONSTRUCTING (v) = needs_ctor;
+	  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (v) = needs_dtor;
+	}
+    }
+
+  return t;
+}
+
+// forked from gcc/cp/tree.cc cp_build_qualified_type_real
+
+/* Make a variant of TYPE, qualified with the TYPE_QUALS.  Handles
+   arrays correctly.  In particular, if TYPE is an array of T's, and
+   TYPE_QUALS is non-empty, returns an array of qualified T's.
+
+   FLAGS determines how to deal with ill-formed qualifications. If
+   tf_ignore_bad_quals is set, then bad qualifications are dropped
+   (this is permitted if TYPE was introduced via a typedef or template
+   type parameter). If bad qualifications are dropped and tf_warning
+   is set, then a warning is issued for non-const qualifications.  If
+   tf_ignore_bad_quals is not set and tf_error is not set, we
+   return error_mark_node. Otherwise, we issue an error, and ignore
+   the qualifications.
+
+   Qualification of a reference type is valid when the reference came
+   via a typedef or template type argument. [dcl.ref] No such
+   dispensation is provided for qualifying a function type.  [dcl.fct]
+   DR 295 queries this and the proposed resolution brings it into line
+   with qualifying a reference.  We implement the DR.  We also behave
+   in a similar manner for restricting non-pointer types.  */
+
+tree
+rs_build_qualified_type_real (tree type, int type_quals,
+			      tsubst_flags_t complain)
+{
+  tree result;
+  int bad_quals = TYPE_UNQUALIFIED;
+
+  if (type == error_mark_node)
+    return type;
+
+  if (type_quals == rs_type_quals (type))
+    return type;
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* In C++, the qualification really applies to the array element
+	 type.  Obtain the appropriately qualified element type.  */
+      tree t;
+      tree element_type
+	= rs_build_qualified_type_real (TREE_TYPE (type), type_quals, complain);
+
+      if (element_type == error_mark_node)
+	return error_mark_node;
+
+      /* See if we already have an identically qualified type.  Tests
+	 should be equivalent to those in check_qualified_type.  */
+      for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+	if (TREE_TYPE (t) == element_type && TYPE_NAME (t) == TYPE_NAME (type)
+	    && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+	    && attribute_list_equal (TYPE_ATTRIBUTES (t),
+				     TYPE_ATTRIBUTES (type)))
+	  break;
+
+      if (!t)
+	{
+	  /* If we already know the dependentness, tell the array type
+	     constructor.  This is important for module streaming, as we cannot
+	     dynamically determine that on read in.  */
+	  t = build_cplus_array_type (element_type, TYPE_DOMAIN (type),
+				      TYPE_DEPENDENT_P_VALID (type)
+					? int (TYPE_DEPENDENT_P (type))
+					: -1);
+
+	  /* Keep the typedef name.  */
+	  if (TYPE_NAME (t) != TYPE_NAME (type))
+	    {
+	      t = build_variant_type_copy (t);
+	      TYPE_NAME (t) = TYPE_NAME (type);
+	      SET_TYPE_ALIGN (t, TYPE_ALIGN (type));
+	      TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type);
+	    }
+	}
+
+      /* Even if we already had this variant, we update
+	 TYPE_NEEDS_CONSTRUCTING and TYPE_HAS_NONTRIVIAL_DESTRUCTOR in case
+	 they changed since the variant was originally created.
+
+	 This seems hokey; if there is some way to use a previous
+	 variant *without* coming through here,
+	 TYPE_NEEDS_CONSTRUCTING will never be updated.  */
+      TYPE_NEEDS_CONSTRUCTING (t)
+	= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type));
+      TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+	= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
+      return t;
+    }
+
+  /* A reference or method type shall not be cv-qualified.
+     [dcl.ref], [dcl.fct].  This used to be an error, but as of DR 295
+     (in CD1) we always ignore extra cv-quals on functions.  */
+
+  /* [dcl.ref/1] Cv-qualified references are ill-formed except when
+     the cv-qualifiers are introduced through the use of a typedef-name
+     ([dcl.typedef], [temp.param]) or decltype-specifier
+     ([dcl.type.decltype]),in which case the cv-qualifiers are
+     ignored.  */
+  if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)
+      && (TYPE_REF_P (type) || FUNC_OR_METHOD_TYPE_P (type)))
+    {
+      if (TYPE_REF_P (type)
+	  && (!typedef_variant_p (type) || FUNC_OR_METHOD_TYPE_P (type)))
+	bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+      type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+    }
+
+  /* But preserve any function-cv-quals on a FUNCTION_TYPE.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    type_quals |= type_memfn_quals (type);
+
+  /* A restrict-qualified type must be a pointer (or reference)
+     to object or incomplete type. */
+  if ((type_quals & TYPE_QUAL_RESTRICT)
+      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+      && TREE_CODE (type) != TYPENAME_TYPE && !INDIRECT_TYPE_P (type))
+    {
+      bad_quals |= TYPE_QUAL_RESTRICT;
+      type_quals &= ~TYPE_QUAL_RESTRICT;
+    }
+
+  if (bad_quals == TYPE_UNQUALIFIED || (complain & tf_ignore_bad_quals))
+    /*OK*/;
+  else if (!(complain & tf_error))
+    return error_mark_node;
+  else
+    {
+      tree bad_type = build_qualified_type (ptr_type_node, bad_quals);
+      error ("%qV qualifiers cannot be applied to %qT", bad_type, type);
+    }
+
+  /* Retrieve (or create) the appropriately qualified variant.  */
+  result = build_qualified_type (type, type_quals);
+
+  return result;
+}
+
+// forked from gcc/cp/c-common.cc vector_targets_convertible_p
+
+/* vector_targets_convertible_p is used for vector pointer types.  The
+   callers perform various checks that the qualifiers are satisfactory,
+   while OTOH vector_targets_convertible_p ignores the number of elements
+   in the vectors.  That's fine with vector pointers as we can consider,
+   say, a vector of 8 elements as two consecutive vectors of 4 elements,
+   and that does not require and conversion of the pointer values.
+   In contrast, vector_types_convertible_p and
+   vector_types_compatible_elements_p are used for vector value types.  */
+/* True if pointers to distinct types T1 and T2 can be converted to
+   each other without an explicit cast.  Only returns true for opaque
+   vector types.  */
+bool
+vector_targets_convertible_p (const_tree t1, const_tree t2)
+{
+  if (VECTOR_TYPE_P (t1) && VECTOR_TYPE_P (t2)
+      && (TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
+      && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
+    return true;
+
+  return false;
+}
+
+// forked from gcc/cp/typeck.cc comp_array_types
+
+/* Compare the array types T1 and T2.  CB says how we should behave when
+   comparing array bounds: bounds_none doesn't allow dimensionless arrays,
+   bounds_either says than any array can be [], bounds_first means that
+   onlt T1 can be an array with unknown bounds.  STRICT is true if
+   qualifiers must match when comparing the types of the array elements.  */
+
+static bool
+comp_array_types (const_tree t1, const_tree t2, compare_bounds_t cb,
+		  bool strict)
+{
+  tree d1;
+  tree d2;
+  tree max1, max2;
+
+  if (t1 == t2)
+    return true;
+
+  /* The type of the array elements must be the same.  */
+  if (strict ? !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+	     : !similar_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return false;
+
+  d1 = TYPE_DOMAIN (t1);
+  d2 = TYPE_DOMAIN (t2);
+
+  if (d1 == d2)
+    return true;
+
+  /* If one of the arrays is dimensionless, and the other has a
+     dimension, they are of different types.  However, it is valid to
+     write:
+
+       extern int a[];
+       int a[3];
+
+     by [basic.link]:
+
+       declarations for an array object can specify
+       array types that differ by the presence or absence of a major
+       array bound (_dcl.array_).  */
+  if (!d1 && d2)
+    return cb >= bounds_either;
+  else if (d1 && !d2)
+    return cb == bounds_either;
+
+  /* Check that the dimensions are the same.  */
+
+  if (!rs_tree_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)))
+    return false;
+  max1 = TYPE_MAX_VALUE (d1);
+  max2 = TYPE_MAX_VALUE (d2);
+
+  if (!rs_tree_equal (max1, max2))
+    return false;
+
+  return true;
+}
+
+// forked from gcc/cp/typeck.cc same_type_ignoring_top_level_qualifiers_p
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+   top-level qualifiers.  */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+  if (type1 == error_mark_node || type2 == error_mark_node)
+    return false;
+  if (type1 == type2)
+    return true;
+
+  type1 = rs_build_qualified_type (type1, TYPE_UNQUALIFIED);
+  type2 = rs_build_qualified_type (type2, TYPE_UNQUALIFIED);
+  return same_type_p (type1, type2);
+}
+
+// forked from gcc/cp/typeck.cc comp_ptr_ttypes_const
+
+/* Return true if TO and FROM (both of which are POINTER_TYPEs or
+   pointer-to-member types) are the same, ignoring cv-qualification at
+   all levels.  CB says how we should behave when comparing array bounds.  */
+
+bool
+comp_ptr_ttypes_const (tree to, tree from, compare_bounds_t cb)
+{
+  bool is_opaque_pointer = false;
+
+  for (;; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (to) != TREE_CODE (from))
+	return false;
+
+      if (TREE_CODE (from) == OFFSET_TYPE
+	  && same_type_p (TYPE_OFFSET_BASETYPE (from),
+			  TYPE_OFFSET_BASETYPE (to)))
+	continue;
+
+      if (VECTOR_TYPE_P (to))
+	is_opaque_pointer = vector_targets_convertible_p (to, from);
+
+      if (TREE_CODE (to) == ARRAY_TYPE
+	  /* Ignore cv-qualification, but if we see e.g. int[3] and int[4],
+	     we must fail.  */
+	  && !comp_array_types (to, from, cb, /*strict=*/false))
+	return false;
+
+      /* CWG 330 says we need to look through arrays.  */
+      if (!TYPE_PTR_P (to) && TREE_CODE (to) != ARRAY_TYPE)
+	return (is_opaque_pointer
+		|| same_type_ignoring_top_level_qualifiers_p (to, from));
+    }
+}
+
+// forked from gcc/cp/typeck.cc similar_type_p
+
+/* Returns nonzero iff TYPE1 and TYPE2 are similar, as per [conv.qual].  */
+
+bool
+similar_type_p (tree type1, tree type2)
+{
+  if (type1 == error_mark_node || type2 == error_mark_node)
+    return false;
+
+  /* Informally, two types are similar if, ignoring top-level cv-qualification:
+     * they are the same type; or
+     * they are both pointers, and the pointed-to types are similar; or
+     * they are both pointers to member of the same class, and the types of
+       the pointed-to members are similar; or
+     * they are both arrays of the same size or both arrays of unknown bound,
+       and the array element types are similar.  */
+
+  if (same_type_ignoring_top_level_qualifiers_p (type1, type2))
+    return true;
+
+  if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+      || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
+      || (TREE_CODE (type1) == ARRAY_TYPE && TREE_CODE (type2) == ARRAY_TYPE))
+    return comp_ptr_ttypes_const (type1, type2, bounds_either);
+
+  return false;
+}
+
+// forked from gcc/cp/typeck.cc structural_comptypes
+// note: this fork only handles strict == COMPARE_STRICT
+// if you pass in any other value for strict i.e. COMPARE_BASE,
+// COMPARE_DERIVED, COMPARE_REDECLARATION or COMPARE_STRUCTURAL
+// see the original function in gcc/cp/typeck.cc and port the required bits
+// specifically under case UNION_TYPE.
+
+/* Subroutine in comptypes.  */
+
+static bool
+structural_comptypes (tree t1, tree t2, int strict)
+{
+  /* Both should be types that are not obviously the same.  */
+  gcc_checking_assert (t1 != t2 && TYPE_P (t1) && TYPE_P (t2));
+
+  if (TYPE_PTRMEMFUNC_P (t1))
+    t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+  if (TYPE_PTRMEMFUNC_P (t2))
+    t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
+  /* Different classes of types can't be compatible.  */
+  if (TREE_CODE (t1) != TREE_CODE (t2))
+    return false;
+
+  /* Qualifiers must match.  For array types, we will check when we
+     recur on the array element types.  */
+  if (TREE_CODE (t1) != ARRAY_TYPE && rs_type_quals (t1) != rs_type_quals (t2))
+    return false;
+  if (TREE_CODE (t1) == FUNCTION_TYPE
+      && type_memfn_quals (t1) != type_memfn_quals (t2))
+    return false;
+  /* Need to check this before TYPE_MAIN_VARIANT.
+     FIXME function qualifiers should really change the main variant.  */
+  if (FUNC_OR_METHOD_TYPE_P (t1))
+    {
+      if (type_memfn_rqual (t1) != type_memfn_rqual (t2))
+	return false;
+      if (/* cxx_dialect >= cxx17 && */
+	  !comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+			      TYPE_RAISES_EXCEPTIONS (t2), ce_type))
+	return false;
+    }
+
+  /* Allow for two different type nodes which have essentially the same
+     definition.  Note that we already checked for equality of the type
+     qualifiers (just above).  */
+  if (TREE_CODE (t1) != ARRAY_TYPE
+      && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+    return true;
+
+  /* Compare the types.  Return false on known not-same. Break on not
+     known.   Never return true from this switch -- you'll break
+     specialization comparison.    */
+  switch (TREE_CODE (t1))
+    {
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+      /* All void and bool types are the same.  */
+      break;
+
+    case OPAQUE_TYPE:
+    case INTEGER_TYPE:
+    case FIXED_POINT_TYPE:
+    case REAL_TYPE:
+      /* With these nodes, we can't determine type equivalence by
+	 looking at what is stored in the nodes themselves, because
+	 two nodes might have different TYPE_MAIN_VARIANTs but still
+	 represent the same type.  For example, wchar_t and int could
+	 have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE,
+	 TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs
+	 and are distinct types. On the other hand, int and the
+	 following typedef
+
+	   typedef int INT __attribute((may_alias));
+
+	 have identical properties, different TYPE_MAIN_VARIANTs, but
+	 represent the same type.  The canonical type system keeps
+	 track of equivalence in this case, so we fall back on it.  */
+      if (TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
+	return false;
+
+      /* We don't need or want the attribute comparison.  */
+      return true;
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+      return false;
+
+    case OFFSET_TYPE:
+      if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
+		      strict & ~COMPARE_REDECLARATION))
+	return false;
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	return false;
+      break;
+
+    case REFERENCE_TYPE:
+      if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2))
+	return false;
+      /* fall through to checks for pointer types */
+      gcc_fallthrough ();
+
+    case POINTER_TYPE:
+      if (TYPE_MODE (t1) != TYPE_MODE (t2)
+	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	return false;
+      break;
+
+    case METHOD_TYPE:
+    case FUNCTION_TYPE:
+      /* Exception specs and memfn_rquals were checked above.  */
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	return false;
+      if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+	return false;
+      break;
+
+    case ARRAY_TYPE:
+      /* Target types must match incl. qualifiers.  */
+      if (!comp_array_types (t1, t2,
+			     ((strict & COMPARE_REDECLARATION) ? bounds_either
+							       : bounds_none),
+			     /*strict=*/true))
+	return false;
+      break;
+
+    case COMPLEX_TYPE:
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	return false;
+      break;
+
+    case VECTOR_TYPE:
+      if (gnu_vector_type_p (t1) != gnu_vector_type_p (t2)
+	  || maybe_ne (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
+	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	return false;
+      break;
+
+    default:
+      return false;
+    }
+
+  /* If we get here, we know that from a target independent POV the
+     types are the same.  Make sure the target attributes are also
+     the same.  */
+  if (!comp_type_attributes (t1, t2))
+    return false;
+
+  return true;
+}
+
+// forked from gcc/cp/typeck.cc comptypes
+
+/* Return true if T1 and T2 are related as allowed by STRICT.  STRICT
+   is a bitwise-or of the COMPARE_* flags.  */
+
+bool
+comptypes (tree t1, tree t2, int strict)
+{
+  gcc_checking_assert (t1 && t2);
+
+  /* TYPE_ARGUMENT_PACKS are not really types.  */
+  gcc_checking_assert (TREE_CODE (t1) != TYPE_ARGUMENT_PACK
+		       && TREE_CODE (t2) != TYPE_ARGUMENT_PACK);
+
+  if (t1 == t2)
+    return true;
+
+  /* Suppress errors caused by previously reported errors.  */
+  if (t1 == error_mark_node || t2 == error_mark_node)
+    return false;
+
+  if (strict == COMPARE_STRICT)
+    {
+      if (TYPE_STRUCTURAL_EQUALITY_P (t1) || TYPE_STRUCTURAL_EQUALITY_P (t2))
+	/* At least one of the types requires structural equality, so
+	   perform a deep check. */
+	return structural_comptypes (t1, t2, strict);
+
+      if (flag_checking && param_use_canonical_types)
+	{
+	  bool result = structural_comptypes (t1, t2, strict);
+
+	  if (result && TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
+	    /* The two types are structurally equivalent, but their
+	       canonical types were different. This is a failure of the
+	       canonical type propagation code.*/
+	    internal_error (
+	      "canonical types differ for identical types %qT and %qT", t1, t2);
+	  else if (!result && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2))
+	    /* Two types are structurally different, but the canonical
+	       types are the same. This means we were over-eager in
+	       assigning canonical types. */
+	    internal_error (
+	      "same canonical type node for different types %qT and %qT", t1,
+	      t2);
+
+	  return result;
+	}
+      if (!flag_checking && param_use_canonical_types)
+	return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+      else
+	return structural_comptypes (t1, t2, strict);
+    }
+  else if (strict == COMPARE_STRUCTURAL)
+    return structural_comptypes (t1, t2, COMPARE_STRICT);
+  else
+    return structural_comptypes (t1, t2, strict);
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index e3522683372..d5cc3186811 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -745,6 +745,106 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 #define TYPE_NAME_STRING(NODE) (IDENTIFIER_POINTER (TYPE_IDENTIFIER (NODE)))
 #define TYPE_NAME_LENGTH(NODE) (IDENTIFIER_LENGTH (TYPE_IDENTIFIER (NODE)))
 
+/* Whether a PARM_DECL represents a local parameter in a
+   requires-expression.  */
+#define CONSTRAINT_VAR_P(NODE) DECL_LANG_FLAG_2 (TREE_CHECK (NODE, PARM_DECL))
+
+/* In a CALL_EXPR appearing in a template, true if Koenig lookup
+   should be performed at instantiation time.  */
+#define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0 (CALL_EXPR_CHECK (NODE))
+
+/* The index of a user-declared parameter in its function, starting at 1.
+   All artificial parameters will have index 0.  */
+#define DECL_PARM_INDEX(NODE) (LANG_DECL_PARM_CHECK (NODE)->index)
+
+/* The level of a user-declared parameter in its function, starting at 1.
+   A parameter of the function will have level 1; a parameter of the first
+   nested function declarator (i.e. t in void f (void (*p)(T t))) will have
+   level 2.  */
+#define DECL_PARM_LEVEL(NODE) (LANG_DECL_PARM_CHECK (NODE)->level)
+
+#define LANG_DECL_PARM_CHECK(NODE) (&DECL_LANG_SPECIFIC (NODE)->u.parm)
+
+/* These flags are used by the conversion code.
+   CONV_IMPLICIT   :  Perform implicit conversions (standard and user-defined).
+   CONV_STATIC     :  Perform the explicit conversions for static_cast.
+   CONV_CONST      :  Perform the explicit conversions for const_cast.
+   CONV_REINTERPRET:  Perform the explicit conversions for reinterpret_cast.
+   CONV_PRIVATE    :  Perform upcasts to private bases.
+   CONV_FORCE_TEMP :  Require a new temporary when converting to the same
+		      aggregate type.  */
+
+#define CONV_IMPLICIT 1
+#define CONV_STATIC 2
+#define CONV_CONST 4
+#define CONV_REINTERPRET 8
+#define CONV_PRIVATE 16
+#define CONV_FORCE_TEMP 32
+#define CONV_FOLD 64
+#define CONV_OLD_CONVERT                                                       \
+  (CONV_IMPLICIT | CONV_STATIC | CONV_CONST | CONV_REINTERPRET)
+#define CONV_C_CAST                                                            \
+  (CONV_IMPLICIT | CONV_STATIC | CONV_CONST | CONV_REINTERPRET | CONV_PRIVATE  \
+   | CONV_FORCE_TEMP)
+#define CONV_BACKEND_CONVERT (CONV_OLD_CONVERT | CONV_FOLD)
+
+/* Used by build_expr_type_conversion to indicate which types are
+   acceptable as arguments to the expression under consideration.  */
+
+#define WANT_INT 1		  /* integer types, including bool */
+#define WANT_FLOAT 2		  /* floating point types */
+#define WANT_ENUM 4		  /* enumerated types */
+#define WANT_POINTER 8		  /* pointer types */
+#define WANT_NULL 16		  /* null pointer constant */
+#define WANT_VECTOR_OR_COMPLEX 32 /* vector or complex types */
+#define WANT_ARITH (WANT_INT | WANT_FLOAT | WANT_VECTOR_OR_COMPLEX)
+
+/* Used with comptypes, and related functions, to guide type
+   comparison.  */
+
+#define COMPARE_STRICT                                                         \
+  0 /* Just check if the types are the                                         \
+       same.  */
+#define COMPARE_BASE                                                           \
+  1 /* Check to see if the second type is                                      \
+       derived from the first.  */
+#define COMPARE_DERIVED                                                        \
+  2 /* Like COMPARE_BASE, but in                                               \
+       reverse.  */
+#define COMPARE_REDECLARATION                                                  \
+  4 /* The comparison is being done when                                       \
+       another declaration of an existing                                      \
+       entity is seen.  */
+#define COMPARE_STRUCTURAL                                                     \
+  8 /* The comparison is intended to be                                        \
+       structural. The actual comparison                                       \
+       will be identical to                                                    \
+       COMPARE_STRICT.  */
+
+/* Used with start function.  */
+#define SF_DEFAULT 0 /* No flags.  */
+#define SF_PRE_PARSED                                                          \
+  1 /* The function declaration has                                            \
+       already been parsed.  */
+#define SF_INCLASS_INLINE                                                      \
+  2 /* The function is an inline, defined                                      \
+       in the class body.  */
+
+/* Used with start_decl's initialized parameter.  */
+#define SD_UNINITIALIZED 0
+#define SD_INITIALIZED 1
+/* Like SD_INITIALIZED, but also mark the new decl as DECL_DECOMPOSITION_P.  */
+#define SD_DECOMPOSITION 2
+#define SD_DEFAULTED 3
+#define SD_DELETED 4
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
+   sense of `same'.  */
+#define same_type_p(TYPE1, TYPE2) comptypes ((TYPE1), (TYPE2), COMPARE_STRICT)
+
+/* Returns true if NODE is a pointer-to-data-member.  */
+#define TYPE_PTRDATAMEM_P(NODE) (TREE_CODE (NODE) == OFFSET_TYPE)
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -810,6 +910,234 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 
 // Above macros are copied from gcc/cp/name-lookup.cc
 
+/* hash traits for declarations.  Hashes potential overload sets via
+   DECL_NAME.  */
+
+struct named_decl_hash : ggc_remove<tree>
+{
+  typedef tree value_type;   /* A DECL or OVERLOAD  */
+  typedef tree compare_type; /* An identifier.  */
+
+  inline static hashval_t hash (const value_type decl);
+  inline static bool equal (const value_type existing, compare_type candidate);
+
+  static const bool empty_zero_p = true;
+  static inline void mark_empty (value_type &p) { p = NULL_TREE; }
+  static inline bool is_empty (value_type p) { return !p; }
+
+  /* Nothing is deletable.  Everything is insertable.  */
+  static bool is_deleted (value_type) { return false; }
+  static void mark_deleted (value_type) { gcc_unreachable (); }
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl_selector
+
+/* Discriminator values for lang_decl.  */
+
+enum lang_decl_selector
+{
+  lds_min,
+  lds_fn,
+  lds_ns,
+  lds_parm,
+  lds_decomp
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl_base
+
+/* Flags shared by all forms of DECL_LANG_SPECIFIC.
+
+   Some of the flags live here only to make lang_decl_min/fn smaller.  Do
+   not make this struct larger than 32 bits.  */
+
+struct GTY (()) lang_decl_base
+{
+  ENUM_BITFIELD (lang_decl_selector) selector : 3;
+  unsigned use_template : 2;
+  unsigned not_really_extern : 1;    /* var or fn */
+  unsigned initialized_in_class : 1; /* var or fn */
+
+  unsigned threadprivate_or_deleted_p : 1; /* var or fn */
+  /* anticipated_p is no longer used for anticipated_decls (fn, type
+     or template).  It is used as DECL_OMP_PRIVATIZED_MEMBER in
+     var.  */
+  unsigned anticipated_p : 1;
+  unsigned friend_or_tls : 1;	      /* var, fn, type or template */
+  unsigned unknown_bound_p : 1;	      /* var */
+  unsigned odr_used : 1;	      /* var or fn */
+  unsigned concept_p : 1;	      /* applies to vars and functions */
+  unsigned var_declared_inline_p : 1; /* var */
+  unsigned dependent_init_p : 1;      /* var */
+
+  /* The following apply to VAR, FUNCTION, TYPE, CONCEPT, & NAMESPACE
+     decls.  */
+  unsigned module_purview_p : 1; /* in module purview (not GMF) */
+  unsigned module_import_p : 1;	 /* from an import */
+  unsigned module_entity_p : 1;	 /* is in the entitity ary &
+				    hash.  */
+  /* VAR_DECL or FUNCTION_DECL has attached decls.     */
+  unsigned module_attached_p : 1;
+
+  /* 12 spare bits.  */
+};
+
+/* True for DECL codes which have template info and access.  */
+#define LANG_DECL_HAS_MIN(NODE)                                                \
+  (VAR_OR_FUNCTION_DECL_P (NODE) || TREE_CODE (NODE) == FIELD_DECL             \
+   || TREE_CODE (NODE) == CONST_DECL || TREE_CODE (NODE) == TYPE_DECL          \
+   || TREE_CODE (NODE) == TEMPLATE_DECL || TREE_CODE (NODE) == USING_DECL      \
+   || TREE_CODE (NODE) == CONCEPT_DECL)
+
+// forked from gcc/cp/cp-tree.h lang_decl_min
+
+/* DECL_LANG_SPECIFIC for the above codes.  */
+
+struct GTY (()) lang_decl_min
+{
+  struct lang_decl_base base; /* 32-bits.  */
+
+  /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
+     THUNK_ALIAS.
+     In a FUNCTION_DECL for which DECL_THUNK_P does not hold,
+     VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this is
+     DECL_TEMPLATE_INFO.  */
+  tree template_info;
+
+  /* In a DECL_THUNK_P FUNCTION_DECL, this is THUNK_VIRTUAL_OFFSET.
+     In a lambda-capture proxy VAR_DECL, this is DECL_CAPTURED_VARIABLE.
+     In a function-scope TREE_STATIC VAR_DECL or IMPLICIT_TYPEDEF_P TYPE_DECL,
+     this is DECL_DISCRIMINATOR.
+     In a DECL_LOCAL_DECL_P decl, this is the namespace decl it aliases.
+     Otherwise, in a class-scope DECL, this is DECL_ACCESS.   */
+  tree access;
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl_fn
+
+/* Additional DECL_LANG_SPECIFIC information for functions.  */
+
+struct GTY (()) lang_decl_fn
+{
+  struct lang_decl_min min;
+
+  /* In a overloaded operator, this is the compressed operator code.  */
+  unsigned ovl_op_code : 6;
+  unsigned global_ctor_p : 1;
+  unsigned global_dtor_p : 1;
+
+  unsigned static_function : 1;
+  unsigned pure_virtual : 1;
+  unsigned defaulted_p : 1;
+  unsigned has_in_charge_parm_p : 1;
+  unsigned has_vtt_parm_p : 1;
+  unsigned pending_inline_p : 1;
+  unsigned nonconverting : 1;
+  unsigned thunk_p : 1;
+
+  unsigned this_thunk_p : 1;
+  unsigned omp_declare_reduction_p : 1;
+  unsigned has_dependent_explicit_spec_p : 1;
+  unsigned immediate_fn_p : 1;
+  unsigned maybe_deleted : 1;
+  unsigned coroutine_p : 1;
+  unsigned implicit_constexpr : 1;
+
+  unsigned spare : 9;
+
+  /* 32-bits padding on 64-bit host.  */
+
+  /* For a non-thunk function decl, this is a tree list of
+     friendly classes. For a thunk function decl, it is the
+     thunked to function decl.  */
+  tree befriending_classes;
+
+  /* For a virtual FUNCTION_DECL for which
+     DECL_THIS_THUNK_P does not hold, this is DECL_THUNKS. Both
+     this pointer and result pointer adjusting thunks are
+     chained here.  This pointer thunks to return pointer thunks
+     will be chained on the return pointer thunk.
+     For a DECL_CONSTUCTOR_P FUNCTION_DECL, this is the base from
+     whence we inherit.  Otherwise, it is the class in which a
+     (namespace-scope) friend is defined (if any).   */
+  tree context;
+
+  union lang_decl_u5
+  {
+    /* In a non-thunk FUNCTION_DECL, this is DECL_CLONED_FUNCTION.  */
+    tree GTY ((tag ("0"))) cloned_function;
+
+    /* In a FUNCTION_DECL for which THUNK_P holds this is the
+       THUNK_FIXED_OFFSET.  */
+    HOST_WIDE_INT GTY ((tag ("1"))) fixed_offset;
+  } GTY ((desc ("%1.thunk_p"))) u5;
+
+  union lang_decl_u3
+  {
+    struct cp_token_cache *GTY ((tag ("1"))) pending_inline_info;
+    tree GTY ((tag ("0"))) saved_auto_return_type;
+  } GTY ((desc ("%1.pending_inline_p"))) u;
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl_ns
+
+/* DECL_LANG_SPECIFIC for namespaces.  */
+
+struct GTY (()) lang_decl_ns
+{
+  struct lang_decl_base base; /* 32 bits.  */
+
+  /* Inline children.  Needs to be va_gc, because of PCH.  */
+  vec<tree, va_gc> *inlinees;
+
+  /* Hash table of bound decls. It'd be nice to have this inline, but
+     as the hash_map has a dtor, we can't then put this struct into a
+     union (until moving to c++11).  */
+  hash_table<named_decl_hash> *bindings;
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl_parm
+
+/* DECL_LANG_SPECIFIC for parameters.  */
+
+struct GTY (()) lang_decl_parm
+{
+  struct lang_decl_base base; /* 32 bits.  */
+  int level;
+  int index;
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl_decomp
+
+/* Additional DECL_LANG_SPECIFIC information for structured bindings.  */
+
+struct GTY (()) lang_decl_decomp
+{
+  struct lang_decl_min min;
+  /* The artificial underlying "e" variable of the structured binding
+     variable.  */
+  tree base;
+};
+
+// forked from gcc/cp/cp-tree.h lang_decl
+
+/* DECL_LANG_SPECIFIC for all types.  It would be nice to just make this a
+   union rather than a struct containing a union as its only field, but
+   tree.h declares it as a struct.  */
+
+struct GTY (()) lang_decl
+{
+  union GTY ((desc ("%h.base.selector"))) lang_decl_u
+  {
+    /* Nothing of only the base type exists.  */
+    struct lang_decl_base GTY ((default)) base;
+    struct lang_decl_min GTY ((tag ("lds_min"))) min;
+    struct lang_decl_fn GTY ((tag ("lds_fn"))) fn;
+    struct lang_decl_ns GTY ((tag ("lds_ns"))) ns;
+    struct lang_decl_parm GTY ((tag ("lds_parm"))) parm;
+    struct lang_decl_decomp GTY ((tag ("lds_decomp"))) decomp;
+  } u;
+};
+
 // forked from gcc/c-family/c-common.h c_fileinfo
 
 /* Information recorded about each file examined during compilation.  */
@@ -958,6 +1286,38 @@ private:
   static tree reveal_node (tree ovl, tree node);
 };
 
+// forked from gcc/cp/cp-tree.h lkp_iterator
+
+/* Iterator over a (potentially) 2 dimensional overload, which is
+   produced by name lookup.  */
+
+class lkp_iterator : public ovl_iterator
+{
+  typedef ovl_iterator parent;
+
+  tree outer;
+
+public:
+  explicit lkp_iterator (tree o) : parent (o, true), outer (maybe_push ()) {}
+
+public:
+  lkp_iterator &operator++ ()
+  {
+    bool repush = !outer;
+
+    if (!parent::operator++ () && !repush)
+      {
+	pop (outer);
+	repush = true;
+      }
+
+    if (repush)
+      outer = maybe_push ();
+
+    return *this;
+  }
+};
+
 // forked from gcc/cp/cp-tree.h treee_pair_s
 
 struct GTY (()) tree_pair_s
@@ -1203,6 +1563,18 @@ enum rs_built_in_function
   RS_BUILT_IN_LAST
 };
 
+// forked from gcc/cp/cp-tree.h compare_bounds_t
+
+/* in typeck.cc */
+/* Says how we should behave when comparing two arrays one of which
+   has unknown bounds.  */
+enum compare_bounds_t
+{
+  bounds_none,
+  bounds_either,
+  bounds_first
+};
+
 extern tree
 convert_to_void (tree expr, impl_conv_void implicit);
 
@@ -1345,6 +1717,33 @@ build_cplus_array_type (tree, tree, int is_dep = -1);
 
 extern bool is_byte_access_type (tree);
 
+extern bool
+comptypes (tree, tree, int);
+
+extern tree canonical_eh_spec			(tree);
+
+extern int cp_tree_operand_length		(const_tree);
+
+extern bool rs_tree_equal			(tree, tree);
+
+extern bool compparms				(const_tree, const_tree);
+
+extern tree
+rs_build_qualified_type_real (tree, int, tsubst_flags_t);
+#define rs_build_qualified_type(TYPE, QUALS)                                   \
+  rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error)
+extern bool cv_qualified_p (const_tree);
+
+extern bool similar_type_p (tree, tree);
+
+extern bool rs_tree_equal (tree, tree);
+
+extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
+
+extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
+
+extern bool comp_ptr_ttypes_const		(tree, tree, compare_bounds_t);
+
 // forked from gcc/cp/cp-tree.h
 
 enum
@@ -1441,6 +1840,18 @@ identifier_p (tree t)
   return NULL;
 }
 
+// forked from gcc/c-family/c-common.h gnu_vector_type_p
+
+/* Return true if TYPE is a vector type that should be subject to the GNU
+   vector extensions (as opposed to a vector type that is used only for
+   the purposes of defining target-specific built-in functions).  */
+
+inline bool
+gnu_vector_type_p (const_tree type)
+{
+  return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
+}
+
 } // namespace Rust
 
 #endif // RUST_TREE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b394fe4571f6c6207c1135da1297bf44f750bbf4

commit b394fe4571f6c6207c1135da1297bf44f750bbf4
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Sun Jul 10 12:38:12 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - get_fileinfo
     - cxx_make_type
     - build_min_array_type
     - identifier_p
    
    Following structs are ported in this changeset:
     - c_fileinfo
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 62 ++++++++++++++++++++++++++++++
 gcc/rust/backend/rust-tree.h  | 89 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 4359c3de987..73c50a4cc2c 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -21,6 +21,7 @@
 #include "stringpool.h"
 #include "attribs.h"
 #include "escaped_string.h"
+#include "libiberty.h"
 
 namespace Rust {
 
@@ -1463,4 +1464,65 @@ maybe_add_lang_type_raw (tree t)
   return true;
 }
 
+// forked from gcc/c-family/c-lex.cc get_fileinfo
+
+static splay_tree file_info_tree;
+
+struct c_fileinfo *
+get_fileinfo (const char *name)
+{
+  splay_tree_node n;
+  struct c_fileinfo *fi;
+
+  if (!file_info_tree)
+    file_info_tree = splay_tree_new (splay_tree_compare_strings, 0,
+				     splay_tree_delete_pointers);
+
+  n = splay_tree_lookup (file_info_tree, (splay_tree_key) name);
+  if (n)
+    return (struct c_fileinfo *) n->value;
+
+  fi = XNEW (struct c_fileinfo);
+  fi->time = 0;
+  fi->interface_only = 0;
+  fi->interface_unknown = 1;
+  splay_tree_insert (file_info_tree, (splay_tree_key) name,
+		     (splay_tree_value) fi);
+  return fi;
+}
+
+// forked from gcc/cp/lex.cc cxx_make_type
+
+tree
+cxx_make_type (enum tree_code code MEM_STAT_DECL)
+{
+  tree t = make_node (code PASS_MEM_STAT);
+
+  if (maybe_add_lang_type_raw (t))
+    {
+      /* Set up some flags that give proper default behavior.  */
+      struct c_fileinfo *finfo = get_fileinfo (LOCATION_FILE (input_location));
+      SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, finfo->interface_unknown);
+      CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
+    }
+
+  if (code == RECORD_TYPE || code == UNION_TYPE)
+    TYPE_CXX_ODR_P (t) = 1;
+
+  return t;
+}
+
+// forked from gcc/cp/tree.cc build_min_array_type
+
+/* Build an ARRAY_TYPE without laying it out.  */
+
+static tree
+build_min_array_type (tree elt_type, tree index_type)
+{
+  tree t = cxx_make_type (ARRAY_TYPE);
+  TREE_TYPE (t) = elt_type;
+  TYPE_DOMAIN (t) = index_type;
+  return t;
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 99ec33c640d..e3522683372 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -23,6 +23,7 @@
 #include "coretypes.h"
 #include "tree.h"
 #include "cpplib.h"
+#include "splay-tree.h"
 
 /* Returns true if NODE is a pointer.  */
 #define TYPE_PTR_P(NODE) (TREE_CODE (NODE) == POINTER_TYPE)
@@ -677,7 +678,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
    pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
    before using this macro.  */
 #define TYPE_PTRMEMFUNC_FN_TYPE(NODE)                                          \
-  (cp_build_qualified_type (TREE_TYPE (TYPE_FIELDS (NODE)),                    \
+  (rs_build_qualified_type (TREE_TYPE (TYPE_FIELDS (NODE)),                    \
 			    rs_type_quals (NODE)))
 
 /* As above, but can be used in places that want an lvalue at the expense
@@ -733,6 +734,17 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 /* The expression in question for a DECLTYPE_TYPE.  */
 #define DECLTYPE_TYPE_EXPR(NODE) (TYPE_VALUES_RAW (DECLTYPE_TYPE_CHECK (NODE)))
 
+#define SET_CLASSTYPE_INTERFACE_UNKNOWN_X(NODE, X)                             \
+  (LANG_TYPE_CLASS_CHECK (NODE)->interface_unknown = !!(X))
+
+/* Nonzero if this class is included from a header file which employs
+   `#pragma interface', and it is not included in its implementation file.  */
+#define CLASSTYPE_INTERFACE_ONLY(NODE)                                         \
+  (LANG_TYPE_CLASS_CHECK (NODE)->interface_only)
+
+#define TYPE_NAME_STRING(NODE) (IDENTIFIER_POINTER (TYPE_IDENTIFIER (NODE)))
+#define TYPE_NAME_LENGTH(NODE) (IDENTIFIER_LENGTH (TYPE_IDENTIFIER (NODE)))
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -798,6 +810,24 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 
 // Above macros are copied from gcc/cp/name-lookup.cc
 
+// forked from gcc/c-family/c-common.h c_fileinfo
+
+/* Information recorded about each file examined during compilation.  */
+
+struct c_fileinfo
+{
+  int time; /* Time spent in the file.  */
+
+  /* Flags used only by C++.
+     INTERFACE_ONLY nonzero means that we are in an "interface" section
+     of the compiler.  INTERFACE_UNKNOWN nonzero means we cannot trust
+     the value of INTERFACE_ONLY.  If INTERFACE_UNKNOWN is zero and
+     INTERFACE_ONLY is zero, it means that we are responsible for
+     exporting definitions that others might need.  */
+  short interface_only;
+  short interface_unknown;
+};
+
 // forked from gcc/cp/name-lookup.h
 
 /* Datatype that represents binding established by a declaration between
@@ -1286,6 +1316,50 @@ inline tree ovl_first (tree) ATTRIBUTE_PURE;
 
 inline bool type_unknown_p (const_tree);
 
+extern tree
+lookup_add (tree fns, tree lookup);
+
+extern tree
+ovl_make (tree fn, tree next = NULL_TREE);
+
+extern int is_overloaded_fn (tree) ATTRIBUTE_PURE;
+
+extern bool maybe_add_lang_type_raw (tree);
+
+extern rs_ref_qualifier type_memfn_rqual (const_tree);
+
+extern bool builtin_pack_fn_p (tree);
+
+extern tree make_conv_op_name (tree);
+
+extern int type_memfn_quals (const_tree);
+
+struct c_fileinfo *
+get_fileinfo (const char *);
+
+extern tree
+cxx_make_type (enum tree_code CXX_MEM_STAT_INFO);
+
+extern tree
+build_cplus_array_type (tree, tree, int is_dep = -1);
+
+extern bool is_byte_access_type (tree);
+
+// forked from gcc/cp/cp-tree.h
+
+enum
+{
+  ce_derived,
+  ce_type,
+  ce_normal,
+  ce_exact
+};
+
+extern tree
+rs_build_qualified_type_real (tree, int, tsubst_flags_t);
+#define rs_build_qualified_type(TYPE, QUALS)                                   \
+  rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error)
+
 extern tree
 rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *);
 #define rs_walk_tree(tp, func, data, pset)                                     \
@@ -1354,6 +1428,19 @@ class_of_this_parm (const_tree fntype)
 {
   return TREE_TYPE (type_of_this_parm (fntype));
 }
+
+// forked from gcc/cp/cp-tree.h identifier_p
+
+/* Return a typed pointer version of T if it designates a
+   C++ front-end identifier.  */
+inline lang_identifier *
+identifier_p (tree t)
+{
+  if (TREE_CODE (t) == IDENTIFIER_NODE)
+    return (lang_identifier *) t;
+  return NULL;
+}
+
 } // namespace Rust
 
 #endif // RUST_TREE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b9c08d705e6174bbbd0670b196d24e00b6f84d33

commit b9c08d705e6174bbbd0670b196d24e00b6f84d33
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Thu Jul 7 11:31:32 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - type_memfn_quals
     - find_parameter_pack_data
     - conv_type_hasher
     - make_conv_op_name
     - builtin_pack_fn_p
     - builtin_pack_call_p
     - has_extra_args_mechanism_p
     - find_parameter_packs_r
     - type_memfn_rqual
     - maybe_add_lang_type_raw
     - type_of_this_parm
     - class_of_this_parm
    
    Following structs, classes and enums are ported in this changeset:
     - cxx_binding
     - c_common_identifier
     - lang_identifier
     - cp_ref_qualifier
     - find_parameter_pack_data
     - conv_type_hasher
    
    Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>

Diff:
---
 gcc/rust/backend/rust-tree.cc | 304 +++++++++++++++++++++++++++++++++++++++++-
 gcc/rust/backend/rust-tree.h  | 149 +++++++++++++++++++--
 2 files changed, 439 insertions(+), 14 deletions(-)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 4b63499c828..4359c3de987 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -1117,9 +1117,6 @@ is_overloaded_fn (tree x)
   if (TREE_CODE (x) == COMPONENT_REF)
     x = TREE_OPERAND (x, 1);
 
-  if ((TREE_CODE (x) == OVERLOAD && !OVL_SINGLE_P (x)))
-    return 2;
-
   return OVL_P (x);
 }
 
@@ -1165,4 +1162,305 @@ lookup_add (tree fns, tree lookup)
 
   return lookup;
 }
+
+// forked from gcc/cp/typeck.cc type_memfn_quals
+
+/* Returns the function-cv-quals for TYPE, which must be a FUNCTION_TYPE or
+   METHOD_TYPE.  */
+
+int
+type_memfn_quals (const_tree type)
+{
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    return TYPE_QUALS (type);
+  else if (TREE_CODE (type) == METHOD_TYPE)
+    return rs_type_quals (class_of_this_parm (type));
+  else
+    gcc_unreachable ();
+}
+
+// forked from gcc/cp/pt.cc find_parameter_pack_data
+
+/* Structure used to track the progress of find_parameter_packs_r.  */
+struct find_parameter_pack_data
+{
+  /* TREE_LIST that will contain all of the parameter packs found by
+     the traversal.  */
+  tree *parameter_packs;
+
+  /* Set of AST nodes that have been visited by the traversal.  */
+  hash_set<tree> *visited;
+
+  /* True iff we're making a type pack expansion.  */
+  bool type_pack_expansion_p;
+
+  /* True iff we found a subtree that has the extra args mechanism.  */
+  bool found_extra_args_tree_p = false;
+};
+
+// forked from gcc/cp/lex.cc conv_type_hasher
+
+/* Hasher for the conversion operator name hash table.  */
+struct conv_type_hasher : ggc_ptr_hash<tree_node>
+{
+  /* Hash NODE, an identifier node in the table.  TYPE_UID is
+     suitable, as we're not concerned about matching canonicalness
+     here.  */
+  static hashval_t hash (tree node)
+  {
+    return (hashval_t) TYPE_UID (TREE_TYPE (node));
+  }
+
+  /* Compare NODE, an identifier node in the table, against TYPE, an
+     incoming TYPE being looked up.  */
+  static bool equal (tree node, tree type) { return TREE_TYPE (node) == type; }
+};
+
+static GTY (()) hash_table<conv_type_hasher> *conv_type_names;
+
+// forked from gcc/cp/lex.cc make_conv_op_name
+
+/* Return an identifier for a conversion operator to TYPE.  We can get
+   from the returned identifier to the type.  We store TYPE, which is
+   not necessarily the canonical type,  which allows us to report the
+   form the user used in error messages.  All these identifiers are
+   not in the identifier hash table, and have the same string name.
+   These IDENTIFIERS are not in the identifier hash table, and all
+   have the same IDENTIFIER_STRING.  */
+
+tree
+make_conv_op_name (tree type)
+{
+  if (type == error_mark_node)
+    return error_mark_node;
+
+  if (conv_type_names == NULL)
+    conv_type_names = hash_table<conv_type_hasher>::create_ggc (31);
+
+  tree *slot
+    = conv_type_names->find_slot_with_hash (type, (hashval_t) TYPE_UID (type),
+					    INSERT);
+  tree identifier = *slot;
+  if (!identifier)
+    {
+      /* Create a raw IDENTIFIER outside of the identifier hash
+	 table.  */
+      identifier = copy_node (conv_op_identifier);
+
+      /* Just in case something managed to bind.  */
+      IDENTIFIER_BINDING (identifier) = NULL;
+
+      /* Hang TYPE off the identifier so it can be found easily later
+	 when performing conversions.  */
+      TREE_TYPE (identifier) = type;
+
+      *slot = identifier;
+    }
+
+  return identifier;
+}
+
+// forked from gcc/cp/pt.cc builtin_pack_fn_p
+
+/* True iff FN is a function representing a built-in variadic parameter
+   pack.  */
+
+bool
+builtin_pack_fn_p (tree fn)
+{
+  if (!fn || TREE_CODE (fn) != FUNCTION_DECL
+      || !DECL_IS_UNDECLARED_BUILTIN (fn))
+    return false;
+
+  if (id_equal (DECL_NAME (fn), "__integer_pack"))
+    return true;
+
+  return false;
+}
+
+// forked from gcc/cp/pt.cc builtin_pack_call_p
+
+/* True iff CALL is a call to a function representing a built-in variadic
+   parameter pack.  */
+
+static bool
+builtin_pack_call_p (tree call)
+{
+  if (TREE_CODE (call) != CALL_EXPR)
+    return false;
+  return builtin_pack_fn_p (CALL_EXPR_FN (call));
+}
+
+// forked from gcc/cp/pt.cc has_extra_args_mechanism_p
+
+/* Return true if the tree T has the extra args mechanism for
+   avoiding partial instantiation.  */
+
+static bool
+has_extra_args_mechanism_p (const_tree t)
+{
+  return false;
+}
+
+// forked from gcc/cp/pt.cc find_parameter_packs_r
+
+/* Identifies all of the argument packs that occur in a template
+   argument and appends them to the TREE_LIST inside DATA, which is a
+   find_parameter_pack_data structure. This is a subroutine of
+   make_pack_expansion and uses_parameter_packs.  */
+static tree
+find_parameter_packs_r (tree *tp, int *walk_subtrees, void *data)
+{
+  tree t = *tp;
+  struct find_parameter_pack_data *ppd
+    = (struct find_parameter_pack_data *) data;
+  bool parameter_pack_p = false;
+
+#define WALK_SUBTREE(NODE)                                                     \
+  rs_walk_tree (&(NODE), &find_parameter_packs_r, ppd, ppd->visited)
+
+  /* Don't look through typedefs; we are interested in whether a
+     parameter pack is actually written in the expression/type we're
+     looking at, not the target type.  */
+  if (TYPE_P (t) && typedef_variant_p (t))
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+
+  /* Identify whether this is a parameter pack or not.  */
+  switch (TREE_CODE (t))
+    {
+    case FIELD_DECL:
+    case PARM_DECL:
+      break;
+
+    case VAR_DECL:
+      break;
+
+    case CALL_EXPR:
+      if (builtin_pack_call_p (t))
+	parameter_pack_p = true;
+      break;
+
+    case BASES:
+      parameter_pack_p = true;
+      break;
+    default:
+      /* Not a parameter pack.  */
+      break;
+    }
+
+  if (parameter_pack_p)
+    {
+      /* Add this parameter pack to the list.  */
+      *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs);
+    }
+
+  if (TYPE_P (t))
+    rs_walk_tree (&TYPE_CONTEXT (t), &find_parameter_packs_r, ppd,
+		  ppd->visited);
+
+  /* This switch statement will return immediately if we don't find a
+     parameter pack.  ??? Should some of these be in cp_walk_subtrees?  */
+  switch (TREE_CODE (t))
+    {
+      case DECL_EXPR: {
+	tree decl = DECL_EXPR_DECL (t);
+	if (is_typedef_decl (decl))
+	  /* Since we stop at typedefs above, we need to look through them at
+	     the point of the DECL_EXPR.  */
+	  rs_walk_tree (&DECL_ORIGINAL_TYPE (decl), &find_parameter_packs_r,
+			ppd, ppd->visited);
+	return NULL_TREE;
+      }
+
+    case INTEGER_TYPE:
+      rs_walk_tree (&TYPE_MAX_VALUE (t), &find_parameter_packs_r, ppd,
+		    ppd->visited);
+      *walk_subtrees = 0;
+      return NULL_TREE;
+
+    case IDENTIFIER_NODE:
+      rs_walk_tree (&TREE_TYPE (t), &find_parameter_packs_r, ppd, ppd->visited);
+      *walk_subtrees = 0;
+      return NULL_TREE;
+
+      case DECLTYPE_TYPE: {
+	/* When traversing a DECLTYPE_TYPE_EXPR, we need to set
+	   type_pack_expansion_p to false so that any placeholders
+	   within the expression don't get marked as parameter packs.  */
+	bool type_pack_expansion_p = ppd->type_pack_expansion_p;
+	ppd->type_pack_expansion_p = false;
+	rs_walk_tree (&DECLTYPE_TYPE_EXPR (t), &find_parameter_packs_r, ppd,
+		      ppd->visited);
+	ppd->type_pack_expansion_p = type_pack_expansion_p;
+	*walk_subtrees = 0;
+	return NULL_TREE;
+      }
+
+    case IF_STMT:
+      rs_walk_tree (&IF_COND (t), &find_parameter_packs_r, ppd, ppd->visited);
+      rs_walk_tree (&THEN_CLAUSE (t), &find_parameter_packs_r, ppd,
+		    ppd->visited);
+      rs_walk_tree (&ELSE_CLAUSE (t), &find_parameter_packs_r, ppd,
+		    ppd->visited);
+      /* Don't walk into IF_STMT_EXTRA_ARGS.  */
+      *walk_subtrees = 0;
+      return NULL_TREE;
+
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+      WALK_SUBTREE (TYPE_RAISES_EXCEPTIONS (t));
+      break;
+
+    default:
+      return NULL_TREE;
+    }
+
+#undef WALK_SUBTREE
+
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/typeck.cc type_memfn_rqual
+
+/* Returns the function-ref-qualifier for TYPE */
+
+rs_ref_qualifier
+type_memfn_rqual (const_tree type)
+{
+  gcc_assert (FUNC_OR_METHOD_TYPE_P (type));
+
+  if (!FUNCTION_REF_QUALIFIED (type))
+    return REF_QUAL_NONE;
+  else if (FUNCTION_RVALUE_QUALIFIED (type))
+    return REF_QUAL_RVALUE;
+  else
+    return REF_QUAL_LVALUE;
+}
+
+// forked from gcc/cp/lex.cc maybe_add_lang_type_raw
+
+/* Add a raw lang_type to T, a type, should it need one.  */
+
+bool
+maybe_add_lang_type_raw (tree t)
+{
+  if (!RECORD_OR_UNION_CODE_P (TREE_CODE (t)))
+    return false;
+
+  auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc (
+    sizeof (struct lang_type)));
+  TYPE_LANG_SPECIFIC (t) = lt;
+
+  if (GATHER_STATISTICS)
+    {
+      tree_node_counts[(int) lang_type] += 1;
+      tree_node_sizes[(int) lang_type] += sizeof (struct lang_type);
+    }
+
+  return true;
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 8d9b9f0d957..99ec33c640d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -22,6 +22,7 @@
 #include "rust-system.h"
 #include "coretypes.h"
 #include "tree.h"
+#include "cpplib.h"
 
 /* Returns true if NODE is a pointer.  */
 #define TYPE_PTR_P(NODE) (TREE_CODE (NODE) == POINTER_TYPE)
@@ -664,6 +665,74 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
    order.  */
 #define MAYBE_CLASS_TYPE_P(T) (WILDCARD_TYPE_P (T) || CLASS_TYPE_P (T))
 
+/* 1 iff FUNCTION_TYPE or METHOD_TYPE has a ref-qualifier (either & or &&). */
+#define FUNCTION_REF_QUALIFIED(NODE)                                           \
+  TREE_LANG_FLAG_4 (FUNC_OR_METHOD_CHECK (NODE))
+
+/* 1 iff FUNCTION_TYPE or METHOD_TYPE has &&-ref-qualifier.  */
+#define FUNCTION_RVALUE_QUALIFIED(NODE)                                        \
+  TREE_LANG_FLAG_5 (FUNC_OR_METHOD_CHECK (NODE))
+
+/* Get the POINTER_TYPE to the METHOD_TYPE associated with this
+   pointer to member function.  TYPE_PTRMEMFUNC_P _must_ be true,
+   before using this macro.  */
+#define TYPE_PTRMEMFUNC_FN_TYPE(NODE)                                          \
+  (cp_build_qualified_type (TREE_TYPE (TYPE_FIELDS (NODE)),                    \
+			    rs_type_quals (NODE)))
+
+/* As above, but can be used in places that want an lvalue at the expense
+   of not necessarily having the correct cv-qualifiers.  */
+#define TYPE_PTRMEMFUNC_FN_TYPE_RAW(NODE) (TREE_TYPE (TYPE_FIELDS (NODE)))
+
+/* True if this type is dependent.  This predicate is only valid if
+   TYPE_DEPENDENT_P_VALID is true.  */
+#define TYPE_DEPENDENT_P(NODE) TYPE_LANG_FLAG_0 (NODE)
+
+/* True if dependent_type_p has been called for this type, with the
+   result that TYPE_DEPENDENT_P is valid.  */
+#define TYPE_DEPENDENT_P_VALID(NODE) TYPE_LANG_FLAG_6 (NODE)
+
+/* Nonzero for _TYPE node means that this type does not have a trivial
+   destructor.  Therefore, destroying an object of this type will
+   involve a call to a destructor.  This can apply to objects of
+   ARRAY_TYPE if the type of the elements needs a destructor.  */
+#define TYPE_HAS_NONTRIVIAL_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_4 (NODE))
+
+/* For FUNCTION_TYPE or METHOD_TYPE, a list of the exceptions that
+   this type can raise.  Each TREE_VALUE is a _TYPE.  The TREE_VALUE
+   will be NULL_TREE to indicate a throw specification of `()', or
+   no exceptions allowed.  For a noexcept specification, TREE_VALUE
+   is NULL_TREE and TREE_PURPOSE is the constant-expression.  For
+   a deferred noexcept-specification, TREE_PURPOSE is a DEFERRED_NOEXCEPT
+   (for templates) or an OVERLOAD list of functions (for implicitly
+   declared functions).  */
+#define TYPE_RAISES_EXCEPTIONS(NODE)                                           \
+  TYPE_LANG_SLOT_1 (FUNC_OR_METHOD_CHECK (NODE))
+
+/* Identifiers map directly to block or class-scope bindings.
+   Namespace-scope bindings are held in hash tables on the respective
+   namespaces.  The identifier bindings are the innermost active
+   binding, from whence you can get the decl and/or implicit-typedef
+   of an elaborated type.   When not bound to a local entity the
+   values are NULL.  */
+#define IDENTIFIER_BINDING(NODE) (LANG_IDENTIFIER_CAST (NODE)->bindings)
+
+#define LANG_IDENTIFIER_CAST(NODE)                                             \
+  ((struct lang_identifier *) IDENTIFIER_NODE_CHECK (NODE))
+
+/* IF_STMT accessors. These give access to the condition of the if
+   statement, the then block of the if statement, and the else block
+   of the if statement if it exists.  */
+#define IF_COND(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 0)
+#define THEN_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 1)
+#define ELSE_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 2)
+#define IF_SCOPE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 3)
+#define IF_STMT_CONSTEXPR_P(NODE) TREE_LANG_FLAG_0 (IF_STMT_CHECK (NODE))
+#define IF_STMT_CONSTEVAL_P(NODE) TREE_LANG_FLAG_2 (IF_STMT_CHECK (NODE))
+
+/* The expression in question for a DECLTYPE_TYPE.  */
+#define DECLTYPE_TYPE_EXPR(NODE) (TYPE_VALUES_RAW (DECLTYPE_TYPE_CHECK (NODE)))
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -689,17 +758,6 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
   ((rs_type_quals (NODE) & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE))             \
    == TYPE_QUAL_CONST)
 
-/* [basic.fundamental]
-
-   Types  bool, char, wchar_t, and the signed and unsigned integer types
-   are collectively called integral types.
-
-   Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
-   types as well, which is incorrect in C++.  Keep these checks in
-   ascending code order.  */
-#define RS_INTEGRAL_TYPE_P(TYPE)                                               \
-  (TREE_CODE (TYPE) == BOOLEAN_TYPE || TREE_CODE (TYPE) == INTEGER_TYPE)
-
 /* Returns true if TYPE is an integral or enumeration name.  Keep
    these checks in ascending code order.  */
 #define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE)                                   \
@@ -740,6 +798,44 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 
 // Above macros are copied from gcc/cp/name-lookup.cc
 
+// forked from gcc/cp/name-lookup.h
+
+/* Datatype that represents binding established by a declaration between
+   a name and a C++ entity.  */
+struct GTY (()) cxx_binding
+{
+  /* Link to chain together various bindings for this name.  */
+  cxx_binding *previous;
+  /* The non-type entity this name is bound to.  */
+  tree value;
+  /* The type entity this name is bound to.  */
+  tree type;
+
+  bool value_is_inherited : 1;
+  bool is_local : 1;
+  bool type_is_hidden : 1;
+};
+
+// forked from gcc/c-family/c-common.h c_common_identifier
+
+/* Identifier part common to the C front ends.  Inherits from
+   tree_identifier, despite appearances.  */
+struct GTY (()) c_common_identifier
+{
+  struct tree_common common;
+  struct cpp_hashnode node; // from cpplib.h
+};
+
+// forked from gcc/cp/cp-tree.h lang_identifier
+
+/* Language-dependent contents of an identifier.  */
+
+struct GTY (()) lang_identifier
+{
+  struct c_common_identifier c_common;
+  cxx_binding *bindings;
+};
+
 // forked from gcc/cp/cp-tree.h tree_overload
 
 /* OVL_HIDDEN_P nodes come before other nodes.  */
@@ -953,6 +1049,15 @@ struct GTY (()) lang_type
 
 namespace Rust {
 
+// forked from gcc/cp/cp-tree.h cp_ref_qualifier
+
+enum rs_ref_qualifier
+{
+  REF_QUAL_NONE = 0,
+  REF_QUAL_LVALUE = 1,
+  REF_QUAL_RVALUE = 2
+};
+
 // forked from gcc/cp/cp-tree.h tsubst_flags
 
 /* Bitmask flags to control type substitution.  */
@@ -1227,6 +1332,28 @@ ovl_first (tree node)
   return node;
 }
 
+// forked from gcc/cp/cp-tree.h type_of_this_parm
+
+/* Return the type of the `this' parameter of FNTYPE.  */
+
+inline tree
+type_of_this_parm (const_tree fntype)
+{
+  function_args_iterator iter;
+  gcc_assert (TREE_CODE (fntype) == METHOD_TYPE);
+  function_args_iter_init (&iter, fntype);
+  return function_args_iter_cond (&iter);
+}
+
+// forked from gcc/cp/cp-tree.h class_of_this_parm
+
+/* Return the class of the `this' parameter of FNTYPE.  */
+
+inline tree
+class_of_this_parm (const_tree fntype)
+{
+  return TREE_TYPE (type_of_this_parm (fntype));
+}
 } // namespace Rust
 
 #endif // RUST_TREE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-08-29 15:32 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f6f1984c3e483e7c00ef8822d310d98ea752d92a

commit f6f1984c3e483e7c00ef8822d310d98ea752d92a
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Tue Jul 5 17:17:57 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - var_in_constexpr_fn
     - member_vec_linear_search
     - member_vec_binary_search
     - is_overloaded_fn
     - ovl_make
     - lookup_add
     - ovl_first
     - type_unknown_p
    
    Following structs, classes and enums are ported in this changeset:
     - tree_overload
     - ovl_iterator
     - tsubst_flags
     - cp_identifier_kind
     - tag_types

Diff:
---
 gcc/rust/backend/rust-tree.cc | 117 +++++++++++
 gcc/rust/backend/rust-tree.h  | 444 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 561 insertions(+)

diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 38c762b76d7..4b63499c828 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -1048,4 +1048,121 @@ init_modules ()
     }
 }
 
+// forked from gcc/cp/constexpr.cc var_in_constexpr_fn
+
+/* True if T was declared in a function declared to be constexpr, and
+   therefore potentially constant in C++14.  */
+
+bool
+var_in_constexpr_fn (tree t)
+{
+  tree ctx = DECL_CONTEXT (t);
+  return (ctx && TREE_CODE (ctx) == FUNCTION_DECL
+	  && DECL_DECLARED_CONSTEXPR_P (ctx));
+}
+
+// forked from gcc/cp/name-lookup.cc member_vec_linear_search
+
+/* Linear search of (unordered) MEMBER_VEC for NAME.  */
+
+static tree
+member_vec_linear_search (vec<tree, va_gc> *member_vec, tree name)
+{
+  for (int ix = member_vec->length (); ix--;)
+    if (tree binding = (*member_vec)[ix])
+      if (OVL_NAME (binding) == name)
+	return binding;
+
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/name-lookup.cc member_vec_binary_search
+
+/* Binary search of (ordered) MEMBER_VEC for NAME.  */
+
+static tree
+member_vec_binary_search (vec<tree, va_gc> *member_vec, tree name)
+{
+  for (unsigned lo = 0, hi = member_vec->length (); lo < hi;)
+    {
+      unsigned mid = (lo + hi) / 2;
+      tree binding = (*member_vec)[mid];
+      tree binding_name = OVL_NAME (binding);
+
+      if (binding_name > name)
+	hi = mid;
+      else if (binding_name < name)
+	lo = mid + 1;
+      else
+	return binding;
+    }
+
+  return NULL_TREE;
+}
+
+// forked from gcc/cp/tree.cc is_overloaded_fn
+
+/* Returns nonzero if X is an expression for a (possibly overloaded)
+   function.  If "f" is a function or function template, "f", "c->f",
+   "c.f", "C::f", and "f<int>" will all be considered possibly
+   overloaded functions.  Returns 2 if the function is actually
+   overloaded, i.e., if it is impossible to know the type of the
+   function without performing overload resolution.  */
+
+int
+is_overloaded_fn (tree x)
+{
+  STRIP_ANY_LOCATION_WRAPPER (x);
+
+  if (TREE_CODE (x) == COMPONENT_REF)
+    x = TREE_OPERAND (x, 1);
+
+  if ((TREE_CODE (x) == OVERLOAD && !OVL_SINGLE_P (x)))
+    return 2;
+
+  return OVL_P (x);
+}
+
+// forked from gcc/cp/tree.cc ovl_make
+
+/* Make a raw overload node containing FN.  */
+
+tree
+ovl_make (tree fn, tree next)
+{
+  tree result = make_node (OVERLOAD);
+
+  if (TREE_CODE (fn) == OVERLOAD)
+    OVL_NESTED_P (result) = true;
+
+  TREE_TYPE (result)
+    = (next || TREE_CODE (fn) == TEMPLATE_DECL ? unknown_type_node
+					       : TREE_TYPE (fn));
+  if (next && TREE_CODE (next) == OVERLOAD && OVL_DEDUP_P (next))
+    OVL_DEDUP_P (result) = true;
+  OVL_FUNCTION (result) = fn;
+  OVL_CHAIN (result) = next;
+  return result;
+}
+
+// forked from gcc/cp/name-lookup.cc lookup_add
+
+/* Add a set of new FNS into a lookup.  */
+
+tree
+lookup_add (tree fns, tree lookup)
+{
+  if (fns == error_mark_node || lookup == error_mark_node)
+    return error_mark_node;
+
+  if (lookup || TREE_CODE (fns) == TEMPLATE_DECL)
+    {
+      lookup = ovl_make (fns, lookup);
+      OVL_LOOKUP_P (lookup) = true;
+    }
+  else
+    lookup = fns;
+
+  return lookup;
+}
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index f65d3ea2b7e..8d9b9f0d957 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -433,6 +433,237 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 /* std::source_location::__impl class.  */
 #define source_location_impl cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
 
+/* These two accessors should only be used by OVL manipulators.
+   Other users should use iterators and convenience functions.  */
+#define OVL_FUNCTION(NODE)                                                     \
+  (((struct tree_overload *) OVERLOAD_CHECK (NODE))->function)
+#define OVL_CHAIN(NODE)                                                        \
+  (((struct tree_overload *) OVERLOAD_CHECK (NODE))->common.chain)
+
+/* If set, this or a subsequent overload contains decls that need deduping.  */
+#define OVL_DEDUP_P(NODE) TREE_LANG_FLAG_0 (OVERLOAD_CHECK (NODE))
+/* If set, this was imported in a using declaration.   */
+#define OVL_USING_P(NODE) TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE))
+/* If set, this overload is a hidden decl.  */
+#define OVL_HIDDEN_P(NODE) TREE_LANG_FLAG_2 (OVERLOAD_CHECK (NODE))
+/* If set, this overload contains a nested overload.  */
+#define OVL_NESTED_P(NODE) TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE))
+/* If set, this overload was constructed during lookup.  */
+#define OVL_LOOKUP_P(NODE) TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE))
+/* If set, this OVL_USING_P overload is exported.  */
+#define OVL_EXPORT_P(NODE) TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE))
+
+/* The first decl of an overload.  */
+#define OVL_FIRST(NODE) ovl_first (NODE)
+/* The name of the overload set.  */
+#define OVL_NAME(NODE) DECL_NAME (OVL_FIRST (NODE))
+
+/* Whether this is a set of overloaded functions.  TEMPLATE_DECLS are
+   always wrapped in an OVERLOAD, so we don't need to check them
+   here.  */
+#define OVL_P(NODE)                                                            \
+  (TREE_CODE (NODE) == FUNCTION_DECL || TREE_CODE (NODE) == OVERLOAD)
+/* Whether this is a single member overload.  */
+#define OVL_SINGLE_P(NODE) (TREE_CODE (NODE) != OVERLOAD || !OVL_CHAIN (NODE))
+
+/* Nonzero means that this type has an X() constructor.  */
+#define TYPE_HAS_DEFAULT_CONSTRUCTOR(NODE)                                     \
+  (LANG_TYPE_CLASS_CHECK (NODE)->has_default_ctor)
+
+/* Nonzero means that NODE (a class type) has a default constructor --
+   but that it has not yet been declared.  */
+#define CLASSTYPE_LAZY_DEFAULT_CTOR(NODE)                                      \
+  (LANG_TYPE_CLASS_CHECK (NODE)->lazy_default_ctor)
+
+/* A FUNCTION_DECL or OVERLOAD for the constructors for NODE.  These
+   are the constructors that take an in-charge parameter.  */
+#define CLASSTYPE_CONSTRUCTORS(NODE)                                           \
+  (get_class_binding_direct (NODE, ctor_identifier))
+
+/* In a TREE_LIST in an attribute list, indicates that the attribute
+   must be applied at instantiation time.  */
+#define ATTR_IS_DEPENDENT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+
+/* In a TREE_LIST in the argument of attribute abi_tag, indicates that the tag
+   was inherited from a template parameter, not explicitly indicated.  */
+#define ABI_TAG_IMPLICIT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+
+/* In a TREE_LIST for a parameter-declaration-list, indicates that all the
+   parameters in the list have declarators enclosed in ().  */
+#define PARENTHESIZED_LIST_P(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+
+/* Non zero if this is a using decl for a dependent scope. */
+#define DECL_DEPENDENT_P(NODE) DECL_LANG_FLAG_0 (USING_DECL_CHECK (NODE))
+
+/* The scope named in a using decl.  */
+#define USING_DECL_SCOPE(NODE) DECL_RESULT_FLD (USING_DECL_CHECK (NODE))
+
+/* The decls named by a using decl.  */
+#define USING_DECL_DECLS(NODE) DECL_INITIAL (USING_DECL_CHECK (NODE))
+
+/* Non zero if the using decl refers to a dependent type.  */
+#define USING_DECL_TYPENAME_P(NODE) DECL_LANG_FLAG_1 (USING_DECL_CHECK (NODE))
+
+/* True if member using decl NODE refers to a non-inherited NODE.  */
+#define USING_DECL_UNRELATED_P(NODE) DECL_LANG_FLAG_2 (USING_DECL_CHECK (NODE))
+
+/* Nonzero if NODE declares a function.  */
+#define DECL_DECLARES_FUNCTION_P(NODE) (TREE_CODE (NODE) == FUNCTION_DECL)
+
+/* Nonzero for a NODE which declares a type.  */
+#define DECL_DECLARES_TYPE_P(NODE) (TREE_CODE (NODE) == TYPE_DECL)
+
+/* Kind bits.  */
+#define IDENTIFIER_KIND_BIT_0(NODE)                                            \
+  TREE_LANG_FLAG_0 (IDENTIFIER_NODE_CHECK (NODE))
+#define IDENTIFIER_KIND_BIT_1(NODE)                                            \
+  TREE_LANG_FLAG_1 (IDENTIFIER_NODE_CHECK (NODE))
+#define IDENTIFIER_KIND_BIT_2(NODE)                                            \
+  TREE_LANG_FLAG_2 (IDENTIFIER_NODE_CHECK (NODE))
+
+/* Used by various search routines.  */
+#define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_4 (IDENTIFIER_NODE_CHECK (NODE))
+
+/* Nonzero if this identifier is used as a virtual function name somewhere
+   (optimizes searches).  */
+#define IDENTIFIER_VIRTUAL_P(NODE)                                             \
+  TREE_LANG_FLAG_5 (IDENTIFIER_NODE_CHECK (NODE))
+
+/* True if this identifier is a reserved word.  C_RID_CODE (node) is
+   then the RID_* value of the keyword.  Value 1.  */
+#define IDENTIFIER_KEYWORD_P(NODE)                                             \
+  ((!IDENTIFIER_KIND_BIT_2 (NODE)) & (!IDENTIFIER_KIND_BIT_1 (NODE))           \
+   & IDENTIFIER_KIND_BIT_0 (NODE))
+
+/* True if this identifier is the name of a constructor or
+   destructor.  Value 2 or 3.  */
+#define IDENTIFIER_CDTOR_P(NODE)                                               \
+  ((!IDENTIFIER_KIND_BIT_2 (NODE)) & IDENTIFIER_KIND_BIT_1 (NODE))
+
+/* True if this identifier is the name of a constructor.  Value 2.  */
+#define IDENTIFIER_CTOR_P(NODE)                                                \
+  (IDENTIFIER_CDTOR_P (NODE) & (!IDENTIFIER_KIND_BIT_0 (NODE)))
+
+/* True if this identifier is the name of a destructor.  Value 3.  */
+#define IDENTIFIER_DTOR_P(NODE)                                                \
+  (IDENTIFIER_CDTOR_P (NODE) & IDENTIFIER_KIND_BIT_0 (NODE))
+
+/* True if this identifier is for any operator name (including
+   conversions).  Value 4, 5, 6 or 7.  */
+#define IDENTIFIER_ANY_OP_P(NODE) (IDENTIFIER_KIND_BIT_2 (NODE))
+
+/* True if this identifier is for an overloaded operator. Values 4, 5.  */
+#define IDENTIFIER_OVL_OP_P(NODE)                                              \
+  (IDENTIFIER_ANY_OP_P (NODE) & (!IDENTIFIER_KIND_BIT_1 (NODE)))
+
+/* True if this identifier is for any assignment. Values 5.  */
+#define IDENTIFIER_ASSIGN_OP_P(NODE)                                           \
+  (IDENTIFIER_OVL_OP_P (NODE) & IDENTIFIER_KIND_BIT_0 (NODE))
+
+/* True if this identifier is the name of a type-conversion
+   operator.  Value 7.  */
+#define IDENTIFIER_CONV_OP_P(NODE)                                             \
+  (IDENTIFIER_ANY_OP_P (NODE) & IDENTIFIER_KIND_BIT_1 (NODE)                   \
+   & (!IDENTIFIER_KIND_BIT_0 (NODE)))
+
+/* True if this identifier is a new or delete operator.  */
+#define IDENTIFIER_NEWDEL_OP_P(NODE)                                           \
+  (IDENTIFIER_OVL_OP_P (NODE)                                                  \
+   && IDENTIFIER_OVL_OP_FLAGS (NODE) & OVL_OP_FLAG_ALLOC)
+
+/* True if this identifier is a new operator.  */
+#define IDENTIFIER_NEW_OP_P(NODE)                                              \
+  (IDENTIFIER_OVL_OP_P (NODE)                                                  \
+   && (IDENTIFIER_OVL_OP_FLAGS (NODE)                                          \
+       & (OVL_OP_FLAG_ALLOC | OVL_OP_FLAG_DELETE))                             \
+	== OVL_OP_FLAG_ALLOC)
+
+/* Nonzero if the class NODE has multiple paths to the same (virtual)
+   base object.  */
+#define CLASSTYPE_DIAMOND_SHAPED_P(NODE)                                       \
+  (LANG_TYPE_CLASS_CHECK (NODE)->diamond_shaped)
+
+/* Nonzero if the class NODE has multiple instances of the same base
+   type.  */
+#define CLASSTYPE_REPEATED_BASE_P(NODE)                                        \
+  (LANG_TYPE_CLASS_CHECK (NODE)->repeated_base)
+
+/* The member function with which the vtable will be emitted:
+   the first noninline non-pure-virtual member function.  NULL_TREE
+   if there is no key function or if this is a class template */
+#define CLASSTYPE_KEY_METHOD(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->key_method)
+
+/* Vector of members.  During definition, it is unordered and only
+   member functions are present.  After completion it is sorted and
+   contains both member functions and non-functions.  STAT_HACK is
+   involved to preserve oneslot per name invariant.  */
+#define CLASSTYPE_MEMBER_VEC(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->members)
+
+/* For class templates, this is a TREE_LIST of all member data,
+   functions, types, and friends in the order of declaration.
+   The TREE_PURPOSE of each TREE_LIST is NULL_TREE for a friend,
+   and the RECORD_TYPE for the class template otherwise.  */
+#define CLASSTYPE_DECL_LIST(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->decl_list)
+
+/* A FUNCTION_DECL or OVERLOAD for the constructors for NODE.  These
+   are the constructors that take an in-charge parameter.  */
+#define CLASSTYPE_CONSTRUCTORS(NODE)                                           \
+  (get_class_binding_direct (NODE, ctor_identifier))
+
+/* A FUNCTION_DECL for the destructor for NODE.  This is the
+   destructors that take an in-charge parameter.  If
+   CLASSTYPE_LAZY_DESTRUCTOR is true, then this entry will be NULL
+   until the destructor is created with lazily_declare_fn.  */
+#define CLASSTYPE_DESTRUCTOR(NODE)                                             \
+  (get_class_binding_direct (NODE, dtor_identifier))
+
+/* Nonzero if NODE has a primary base class, i.e., a base class with
+   which it shares the virtual function table pointer.  */
+#define CLASSTYPE_HAS_PRIMARY_BASE_P(NODE)                                     \
+  (CLASSTYPE_PRIMARY_BINFO (NODE) != NULL_TREE)
+
+/* If non-NULL, this is the binfo for the primary base class, i.e.,
+   the base class which contains the virtual function table pointer
+   for this class.  */
+#define CLASSTYPE_PRIMARY_BINFO(NODE)                                          \
+  (LANG_TYPE_CLASS_CHECK (NODE)->primary_base)
+
+/* A vector of BINFOs for the direct and indirect virtual base classes
+   that this type uses in a post-order depth-first left-to-right
+   order.  (In other words, these bases appear in the order that they
+   should be initialized.)  */
+#define CLASSTYPE_VBASECLASSES(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->vbases)
+
+/* The type corresponding to NODE when NODE is used as a base class,
+   i.e., NODE without virtual base classes or tail padding.  */
+#define CLASSTYPE_AS_BASE(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->as_base)
+
+/* Nonzero if NODE is a user-defined conversion operator.  */
+#define DECL_CONV_FN_P(NODE) IDENTIFIER_CONV_OP_P (DECL_NAME (NODE))
+
+/* The type to which conversion operator FN converts to.   */
+#define DECL_CONV_FN_TYPE(FN)                                                  \
+  TREE_TYPE ((gcc_checking_assert (DECL_CONV_FN_P (FN)), DECL_NAME (FN)))
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
+   sense of `same'.  */
+#define same_type_p(TYPE1, TYPE2) comptypes ((TYPE1), (TYPE2), COMPARE_STRICT)
+
+/* Nonzero if T is a type that could resolve to any kind of concrete type
+   at instantiation time.  */
+#define WILDCARD_TYPE_P(T)                                                     \
+  (TREE_CODE (T) == TEMPLATE_TYPE_PARM || TREE_CODE (T) == TYPENAME_TYPE       \
+   || TREE_CODE (T) == TYPEOF_TYPE                                             \
+   || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM                            \
+   || TREE_CODE (T) == DECLTYPE_TYPE                                           \
+   || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
+
+/* Nonzero if T is a class (or struct or union) type.  Also nonzero
+   for template type parameters, typename types, and instantiated
+   template template parameters.  Keep these checks in ascending code
+   order.  */
+#define MAYBE_CLASS_TYPE_P(T) (WILDCARD_TYPE_P (T) || CLASS_TYPE_P (T))
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -481,6 +712,126 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
 
 // Above macros are copied from gcc/c-family/c-common.h
 
+// Below macros are copied from gcc/cp/name-lookup.cc
+
+/* Create an overload suitable for recording an artificial TYPE_DECL
+   and another decl.  We use this machanism to implement the struct
+   stat hack.  */
+
+#define STAT_HACK_P(N) ((N) && TREE_CODE (N) == OVERLOAD && OVL_LOOKUP_P (N))
+#define STAT_TYPE_VISIBLE_P(N) TREE_USED (OVERLOAD_CHECK (N))
+#define STAT_TYPE(N) TREE_TYPE (N)
+#define STAT_DECL(N) OVL_FUNCTION (N)
+#define STAT_VISIBLE(N) OVL_CHAIN (N)
+#define MAYBE_STAT_DECL(N) (STAT_HACK_P (N) ? STAT_DECL (N) : N)
+#define MAYBE_STAT_TYPE(N) (STAT_HACK_P (N) ? STAT_TYPE (N) : NULL_TREE)
+
+/* When a STAT_HACK_P is true, OVL_USING_P and OVL_EXPORT_P are valid
+   and apply to the hacked type.  */
+
+/* For regular (maybe) overloaded functions, we have OVL_HIDDEN_P.
+   But we also need to indicate hiddenness on implicit type decls
+   (injected friend classes), and (coming soon) decls injected from
+   block-scope externs.  It is too awkward to press the existing
+   overload marking for that.  If we have a hidden non-function, we
+   always create a STAT_HACK, and use these two markers as needed.  */
+#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N)
+#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N)
+
+// Above macros are copied from gcc/cp/name-lookup.cc
+
+// forked from gcc/cp/cp-tree.h tree_overload
+
+/* OVL_HIDDEN_P nodes come before other nodes.  */
+
+struct GTY (()) tree_overload
+{
+  struct tree_common common;
+  tree function;
+};
+
+// forked from gcc/cp/cp-tree.h ovl_iterator
+
+class ovl_iterator
+{
+  tree ovl;
+  const bool allow_inner; /* Only used when checking.  */
+
+public:
+  explicit ovl_iterator (tree o, bool allow = false)
+    : ovl (o), allow_inner (allow)
+  {}
+
+public:
+  operator bool () const { return ovl; }
+  ovl_iterator &operator++ ()
+  {
+    ovl = TREE_CODE (ovl) != OVERLOAD ? NULL_TREE : OVL_CHAIN (ovl);
+    return *this;
+  }
+  tree operator* () const
+  {
+    tree fn = TREE_CODE (ovl) != OVERLOAD ? ovl : OVL_FUNCTION (ovl);
+
+    /* Check this is not an unexpected 2-dimensional overload.  */
+    gcc_checking_assert (allow_inner || TREE_CODE (fn) != OVERLOAD);
+
+    return fn;
+  }
+  bool operator== (const ovl_iterator &o) const { return ovl == o.ovl; }
+  tree get_using () const
+  {
+    gcc_checking_assert (using_p ());
+    return ovl;
+  }
+
+public:
+  /* Whether this overload was introduced by a using decl.  */
+  bool using_p () const
+  {
+    return (TREE_CODE (ovl) == USING_DECL
+	    || (TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl)));
+  }
+  /* Whether this using is being exported.  */
+  bool exporting_p () const { return OVL_EXPORT_P (get_using ()); }
+
+  bool hidden_p () const
+  {
+    return TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl);
+  }
+
+public:
+  tree remove_node (tree head) { return remove_node (head, ovl); }
+  tree reveal_node (tree head) { return reveal_node (head, ovl); }
+
+protected:
+  /* If we have a nested overload, point at the inner overload and
+     return the next link on the outer one.  */
+  tree maybe_push ()
+  {
+    tree r = NULL_TREE;
+
+    if (ovl && TREE_CODE (ovl) == OVERLOAD && OVL_NESTED_P (ovl))
+      {
+	r = OVL_CHAIN (ovl);
+	ovl = OVL_FUNCTION (ovl);
+      }
+    return r;
+  }
+  /* Restore an outer nested overload.  */
+  void pop (tree outer)
+  {
+    gcc_checking_assert (!ovl);
+    ovl = outer;
+  }
+
+private:
+  /* We make these static functions to avoid the address of the
+     iterator escaping the local context.  */
+  static tree remove_node (tree head, tree node);
+  static tree reveal_node (tree ovl, tree node);
+};
+
 // forked from gcc/cp/cp-tree.h treee_pair_s
 
 struct GTY (()) tree_pair_s
@@ -602,6 +953,71 @@ struct GTY (()) lang_type
 
 namespace Rust {
 
+// forked from gcc/cp/cp-tree.h tsubst_flags
+
+/* Bitmask flags to control type substitution.  */
+enum tsubst_flags
+{
+  tf_none = 0,			/* nothing special */
+  tf_error = 1 << 0,		/* give error messages  */
+  tf_warning = 1 << 1,		/* give warnings too  */
+  tf_ignore_bad_quals = 1 << 2, /* ignore bad cvr qualifiers */
+  tf_keep_type_decl = 1 << 3,	/* retain typedef type decls
+				   (make_typename_type use) */
+  tf_ptrmem_ok = 1 << 4,	/* pointers to member ok (internal
+				   instantiate_type use) */
+  tf_user = 1 << 5,		/* found template must be a user template
+				   (lookup_template_class use) */
+  tf_conv = 1 << 6,		/* We are determining what kind of
+				   conversion might be permissible,
+				   not actually performing the
+				   conversion.  */
+  tf_decltype = 1 << 7,		/* We are the operand of decltype.
+				   Used to implement the special rules
+				   for calls in decltype (5.2.2/11).  */
+  tf_partial = 1 << 8,		/* Doing initial explicit argument
+				   substitution in fn_type_unification.  */
+  tf_fndecl_type = 1 << 9,	/* Substituting the type of a function
+				   declaration.  */
+  tf_no_cleanup = 1 << 10,	/* Do not build a cleanup
+				   (build_target_expr and friends) */
+  tf_norm = 1 << 11,		/* Build diagnostic information during
+				   constraint normalization.  */
+  /* Convenient substitution flags combinations.  */
+  tf_warning_or_error = tf_warning | tf_error
+};
+
+// forked from gcc/cp/cp-tree.h cp_identifier_kind
+
+/* Kinds of identifiers.  Values are carefully chosen.  */
+enum cp_identifier_kind
+{
+  cik_normal = 0,	      /* Not a special identifier.  */
+  cik_keyword = 1,	      /* A keyword.  */
+  cik_ctor = 2,		      /* Constructor (in-chg, complete or base).  */
+  cik_dtor = 3,		      /* Destructor (in-chg, deleting, complete or
+				 base).  */
+  cik_simple_op = 4,	      /* Non-assignment operator name.  */
+  cik_assign_op = 5,	      /* An assignment operator name.  */
+  cik_conv_op = 6,	      /* Conversion operator name.  */
+  cik_reserved_for_udlit = 7, /* Not yet in use  */
+  cik_max
+};
+
+// forked from gcc/cp/cp-tree.h tag_types
+
+/* An enumeration of the kind of tags that C++ accepts.  */
+enum tag_types
+{
+  none_type = 0, /* Not a tag type.  */
+  record_type,	 /* "struct" types.  */
+  class_type,	 /* "class" types.  */
+  union_type,	 /* "union" types.  */
+  enum_type,	 /* "enum" types.  */
+  typename_type, /* "typename" types.  */
+  scope_type	 /* namespace or tagged type name followed by :: */
+};
+
 // forked from gcc/cp/cp-tree.h tsubst_flags_t
 
 /* This type is used for parameters and variables which hold
@@ -752,11 +1168,19 @@ extern bool var_in_maybe_constexpr_fn (tree);
 extern int
 rs_type_quals (const_tree type);
 
+inline bool type_unknown_p (const_tree);
+
 extern bool decl_maybe_constant_var_p (tree);
 
 extern void
 init_modules ();
 
+extern bool var_in_constexpr_fn (tree);
+
+inline tree ovl_first (tree) ATTRIBUTE_PURE;
+
+inline bool type_unknown_p (const_tree);
+
 extern tree
 rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *);
 #define rs_walk_tree(tp, func, data, pset)                                     \
@@ -783,6 +1207,26 @@ rs_expr_loc_or_input_loc (const_tree t)
   return rs_expr_loc_or_loc (t, input_location);
 }
 
+// forked from gcc/cp/cp-tree.h type_unknown_p
+
+inline bool
+type_unknown_p (const_tree expr)
+{
+  return TREE_TYPE (expr) == unknown_type_node;
+}
+
+// forked from gcc/cp/cp-tree.h ovl_first
+
+/* Inline bodies.  */
+
+inline tree
+ovl_first (tree node)
+{
+  while (TREE_CODE (node) == OVERLOAD)
+    node = OVL_FUNCTION (node);
+  return node;
+}
+
 } // namespace Rust
 
 #endif // RUST_TREE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1()
@ 2022-06-30 18:50 Thomas Schwinge
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Schwinge @ 2022-06-30 18:50 UTC (permalink / raw)
  To: gcc-cvs

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

commit 2a7a0589f62ab9157d9f862ec2fd7d680c53c5f3
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date:   Sat Jun 25 11:56:42 2022 +0100

    gccrs const folding port: continue porting potential_constant_expression_1()
    
    Following functions are ported in this changeset:
     - maybe_constexpr_fn
     - get_nth_callarg
     - var_in_maybe_constexpr_fn
     - array_type_nelts_top
     - builtin_valid_in_constant_expr_p
     - decl_maybe_constant_var_p
     - cp_type_quals

Diff:
---
 gcc/rust/backend/rust-constexpr.cc |  40 +++++++++++++
 gcc/rust/backend/rust-tree.cc      | 111 ++++++++++++++++++++++++++++++++++++-
 gcc/rust/backend/rust-tree.h       |  75 +++++++++++++++++++++++--
 3 files changed, 219 insertions(+), 7 deletions(-)

diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index f77fb3a8e6d..53c6ef6a668 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -397,5 +397,45 @@ get_function_named_in_call (tree t)
   return fun;
 }
 
+// forked from gcc/cp/constexpr.cc maybe_constexpr_fn
+
+/* True if a function might be declared constexpr  */
+
+bool
+maybe_constexpr_fn (tree t)
+{
+  return (DECL_DECLARED_CONSTEXPR_P (t));
+}
+
+// forked from gcc/cp/constexpr.cc get_nth_callarg
+
+/* We have an expression tree T that represents a call, either CALL_EXPR.
+  Return the Nth argument.  */
+
+inline tree
+get_nth_callarg (tree t, int n)
+{
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      return CALL_EXPR_ARG (t, n);
+
+    default:
+      gcc_unreachable ();
+      return NULL;
+    }
+}
+
+// forked from gcc/cp/constexpr.cc var_in_maybe_constexpr_fn
+
+/* True if T was declared in a function that might be constexpr: either a
+   function that was declared constexpr.  */
+
+bool
+var_in_maybe_constexpr_fn (tree t)
+{
+  return (DECL_FUNCTION_SCOPE_P (t) && maybe_constexpr_fn (DECL_CONTEXT (t)));
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index a71b584618c..3d71e19fe82 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -766,7 +766,7 @@ out:
    locations.  */
 
 location_t
-cp_expr_location (const_tree t_)
+rs_expr_location (const_tree t_)
 {
   tree t = CONST_CAST_TREE (t_);
   if (t == NULL_TREE)
@@ -775,7 +775,7 @@ cp_expr_location (const_tree t_)
   return EXPR_LOCATION (t);
 }
 
-// forked from gcc/cp/class.cc
+// forked from gcc/cp/class.cc is_really_empty_class
 
 /* Returns true if TYPE contains no actual data, just various
    possible combinations of empty classes.  If IGNORE_VPTR is true,
@@ -848,4 +848,111 @@ array_type_nelts_top (tree type)
 			  array_type_nelts (type), size_one_node);
 }
 
+// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
+
+/* Test whether DECL is a builtin that may appear in a
+   constant-expression. */
+
+bool
+builtin_valid_in_constant_expr_p (const_tree decl)
+{
+  STRIP_ANY_LOCATION_WRAPPER (decl);
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    /* Not a function.  */
+    return false;
+  if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
+    {
+      if (fndecl_built_in_p (decl, BUILT_IN_FRONTEND))
+	switch (DECL_FE_FUNCTION_CODE (decl))
+	  {
+	  case RS_BUILT_IN_IS_CONSTANT_EVALUATED:
+	  case RS_BUILT_IN_SOURCE_LOCATION:
+	  case RS_BUILT_IN_IS_CORRESPONDING_MEMBER:
+	  case RS_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS:
+	    return true;
+	  default:
+	    break;
+	  }
+      /* Not a built-in.  */
+      return false;
+    }
+  switch (DECL_FUNCTION_CODE (decl))
+    {
+      /* These always have constant results like the corresponding
+	 macros/symbol.  */
+    case BUILT_IN_FILE:
+    case BUILT_IN_FUNCTION:
+    case BUILT_IN_LINE:
+
+      /* The following built-ins are valid in constant expressions
+	 when their arguments are.  */
+    case BUILT_IN_ADD_OVERFLOW_P:
+    case BUILT_IN_SUB_OVERFLOW_P:
+    case BUILT_IN_MUL_OVERFLOW_P:
+
+      /* These have constant results even if their operands are
+	 non-constant.  */
+    case BUILT_IN_CONSTANT_P:
+    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+      return true;
+    default:
+      return false;
+    }
+}
+
+// forked from gcc/cp/decl2.cc decl_maybe_constant_var_p
+
+/* Returns true if DECL could be a symbolic constant variable, depending on
+   its initializer.  */
+
+bool
+decl_maybe_constant_var_p (tree decl)
+{
+  tree type = TREE_TYPE (decl);
+  if (!VAR_P (decl))
+    return false;
+  if (DECL_DECLARED_CONSTEXPR_P (decl))
+    return true;
+  if (DECL_HAS_VALUE_EXPR_P (decl))
+    /* A proxy isn't constant.  */
+    return false;
+  if (TYPE_REF_P (type))
+    /* References can be constant.  */;
+  else if (RS_TYPE_CONST_NON_VOLATILE_P (type)
+	   && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+    /* And const integers.  */;
+  else
+    return false;
+
+  if (DECL_INITIAL (decl) && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+    /* We know the initializer, and it isn't constant.  */
+    return false;
+  else
+    return true;
+}
+
+// forked from gcc/cp/typeck.cc cp_type_quals
+
+/* Returns the type qualifiers for this type, including the qualifiers on the
+   elements for an array type.  */
+
+int
+rs_type_quals (const_tree type)
+{
+  int quals;
+  /* This CONST_CAST is okay because strip_array_types returns its
+     argument unmodified and we assign it to a const_tree.  */
+  type = strip_array_types (CONST_CAST_TREE (type));
+  if (type == error_mark_node
+      /* Quals on a FUNCTION_TYPE are memfn quals.  */
+      || TREE_CODE (type) == FUNCTION_TYPE)
+    return TYPE_UNQUALIFIED;
+  quals = TYPE_QUALS (type);
+  /* METHOD and REFERENCE_TYPEs should never have quals.  */
+  gcc_assert (
+    (TREE_CODE (type) != METHOD_TYPE && !TYPE_REF_P (type))
+    || ((quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) == TYPE_UNQUALIFIED));
+  return quals;
+}
+
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index b5640907e35..a667cbfc8ad 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -149,6 +149,13 @@
 /* Nonzero if this class is "empty" in the sense of the C++ ABI.  */
 #define CLASSTYPE_EMPTY_P(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->empty_p)
 
+/* True if DECL is declared 'constexpr'.  */
+#define DECL_DECLARED_CONSTEXPR_P(DECL)                                        \
+  DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (DECL))
+
+#define VAR_OR_FUNCTION_DECL_CHECK(NODE)                                       \
+  TREE_CHECK2 (NODE, VAR_DECL, FUNCTION_DECL)
+
 // Below macros are copied from gcc/c-family/c-common.h
 
 /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
@@ -162,6 +169,39 @@
 #define DECL_UNNAMED_BIT_FIELD(NODE)                                           \
   (DECL_C_BIT_FIELD (NODE) && !DECL_NAME (NODE))
 
+/* 1 iff NODE is function-local.  */
+#define DECL_FUNCTION_SCOPE_P(NODE)                                            \
+  (DECL_CONTEXT (NODE) && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL)
+
+/* Nonzero if this type is const-qualified, but not
+   volatile-qualified.  Other qualifiers are ignored.  This macro is
+   used to test whether or not it is OK to bind an rvalue to a
+   reference.  */
+#define RS_TYPE_CONST_NON_VOLATILE_P(NODE)                                     \
+  ((rs_type_quals (NODE) & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE))             \
+   == TYPE_QUAL_CONST)
+
+/* [basic.fundamental]
+
+   Types  bool, char, wchar_t, and the signed and unsigned integer types
+   are collectively called integral types.
+
+   Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
+   types as well, which is incorrect in C++.  Keep these checks in
+   ascending code order.  */
+#define RS_INTEGRAL_TYPE_P(TYPE)                                               \
+  (TREE_CODE (TYPE) == BOOLEAN_TYPE || TREE_CODE (TYPE) == INTEGER_TYPE)
+
+/* Returns true if TYPE is an integral or enumeration name.  Keep
+   these checks in ascending code order.  */
+#define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE)                                   \
+  (TREE_CODE (TYPE) == ENUMERAL_TYPE || RS_INTEGRAL_TYPE_P (TYPE))
+
+/* Nonzero for a VAR_DECL that was initialized with a
+   constant-expression.  */
+#define DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P(NODE)                        \
+  (TREE_LANG_FLAG_2 (VAR_DECL_CHECK (NODE)))
+
 // Above macros are copied from gcc/c-family/c-common.h
 
 // forked from gcc/cp/cp-tree.h treee_pair_s
@@ -324,6 +364,17 @@ enum impl_conv_void
   ICV_THIRD_IN_FOR    /* for increment expression */
 };
 
+/* BUILT_IN_FRONTEND function codes.  */
+enum rs_built_in_function
+{
+  RS_BUILT_IN_IS_CONSTANT_EVALUATED,
+  RS_BUILT_IN_INTEGER_PACK,
+  RS_BUILT_IN_IS_CORRESPONDING_MEMBER,
+  RS_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
+  RS_BUILT_IN_SOURCE_LOCATION,
+  RS_BUILT_IN_LAST
+};
+
 extern tree
 convert_to_void (tree expr, impl_conv_void implicit);
 
@@ -405,13 +456,27 @@ pointer_offset_expression (tree base_tree, tree index_tree, location_t locus);
    but not all node kinds do (e.g. constants, and references to
    params, locals, etc), so we stash a copy here.  */
 
-extern location_t cp_expr_location (const_tree);
+extern location_t rs_expr_location (const_tree);
 
 extern int
 is_empty_class (tree type);
 
 extern tree array_type_nelts_top (tree);
 
+extern bool
+is_really_empty_class (tree, bool);
+
+extern bool builtin_valid_in_constant_expr_p (const_tree);
+
+extern bool maybe_constexpr_fn (tree);
+
+extern bool var_in_maybe_constexpr_fn (tree);
+
+extern int
+rs_type_quals (const_tree type);
+
+extern bool decl_maybe_constant_var_p (tree);
+
 extern tree
 rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *);
 #define rs_walk_tree(tp, func, data, pset)                                     \
@@ -422,9 +487,9 @@ rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *);
 // forked from gcc/cp/cp-tree.h cp_expr_loc_or_loc
 
 inline location_t
-cp_expr_loc_or_loc (const_tree t, location_t or_loc)
+rs_expr_loc_or_loc (const_tree t, location_t or_loc)
 {
-  location_t loc = cp_expr_location (t);
+  location_t loc = rs_expr_location (t);
   if (loc == UNKNOWN_LOCATION)
     loc = or_loc;
   return loc;
@@ -433,9 +498,9 @@ cp_expr_loc_or_loc (const_tree t, location_t or_loc)
 // forked from gcc/cp/cp-tree.h cp_expr_loc_or_input_loc
 
 inline location_t
-cp_expr_loc_or_input_loc (const_tree t)
+rs_expr_loc_or_input_loc (const_tree t)
 {
-  return cp_expr_loc_or_loc (t, input_location);
+  return rs_expr_loc_or_loc (t, input_location);
 }
 
 } // namespace Rust


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-08-29 15:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-29 15:32 [gcc/devel/rust/master] gccrs const folding port: continue porting potential_constant_expression_1() Thomas Schwinge
  -- strict thread matches above, loose matches on Subject: below --
2022-08-29 15:33 Thomas Schwinge
2022-08-29 15:33 Thomas Schwinge
2022-08-29 15:32 Thomas Schwinge
2022-08-29 15:32 Thomas Schwinge
2022-08-29 15:32 Thomas Schwinge
2022-08-29 15:32 Thomas Schwinge
2022-08-29 15:32 Thomas Schwinge
2022-08-29 15:32 Thomas Schwinge
2022-06-30 18:50 Thomas Schwinge

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).