On Tue, Apr 30, 2024 at 1:50 PM Jason Merrill <ja...@redhat.com> wrote: > > On 3/15/24 01:15, Ken Matsui wrote: > > Added diagnostics for build_invoke. > > > > Ok for 15? > > Thanks, just a few tweaks needed. Will you have time to make them? Or > Patrick?
I believe I will have time later next week. Thank you so much for your review! > > [...] > > diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc > > index 98c10e6a8b5..2282ce71c06 100644 > > --- a/gcc/cp/method.cc > > +++ b/gcc/cp/method.cc > > @@ -1928,6 +1928,162 @@ build_trait_object (tree type) > > return build_stub_object (type); > > } > > > > +/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...). > > If the > > + given is not invocable, returns error_mark_node. */ > > + > > +tree > > +build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain) > > +{ > > + if (error_operand_p (fn_type) || error_operand_p (arg_types)) > > + return error_mark_node; > > + > > + gcc_assert (TYPE_P (fn_type)); > > + gcc_assert (TREE_CODE (arg_types) == TREE_VEC); > > + > > + /* Access check is required to determine if the given is invocable. */ > > + deferring_access_check_sentinel acs (dk_no_deferred); > > + > > + /* INVOKE is an unevaluated context. */ > > + cp_unevaluated cp_uneval_guard; > > + > > + bool is_ptrdatamem; > > + bool is_ptrmemfunc; > > + if (TREE_CODE (fn_type) == REFERENCE_TYPE) > > + { > > + tree deref_fn_type = TREE_TYPE (fn_type); > > + is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type); > > + is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type); > > + > > + /* Dereference fn_type if it is a pointer to member. */ > > + if (is_ptrdatamem || is_ptrmemfunc) > > + fn_type = deref_fn_type; > > + } > > + else > > + { > > + is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type); > > + is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type); > > + } > > + > > + if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1) > > + { > > + if (complain & tf_error) > > + error ("pointer to data member type %qT can only be invoked with " > > + "one argument", fn_type); > > + return error_mark_node; > > + } > > + > > + if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0) > > + { > > + if (complain & tf_error) > > + error ("pointer to member function type %qT must be invoked with " > > + "at least one argument", fn_type); > > + return error_mark_node; > > + } > > + > > + /* Construct an expression of a pointer to member. */ > > + tree ptrmem_expr; > > + if (is_ptrdatamem || is_ptrmemfunc) > > + { > > + tree datum_type = TREE_VEC_ELT (arg_types, 0); > > + > > + /* datum must be a class type or a reference/pointer to a class > > type. */ > > + if (TYPE_REF_P (datum_type) || POINTER_TYPE_P (datum_type)) > > + { > > + if (!CLASS_TYPE_P (TREE_TYPE (datum_type))) > > + { > > + if (complain & tf_error) > > + error ("datum type %qT of a pointer to member must be a class" > > I don't see the term "datum" anywhere in [func.require], let's refer to > the "first argument" instead. > > > + "type or a reference/pointer to a class type", > > + datum_type); > > + return error_mark_node; > > + } > > + } > > + else if (!CLASS_TYPE_P (datum_type)) > > + { > > + if (complain & tf_error) > > + error ("datum type %qT of a pointer to member must be a class" > > + "type or a reference/pointer to a class type", > > + datum_type); > > + return error_mark_node; > > + } > > + > > + bool is_refwrap = false; > > + if (CLASS_TYPE_P (datum_type)) > > + { > > + /* 1.2 & 1.5: Handle std::reference_wrapper. */ > > + tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type)); > > + if (decl_in_std_namespace_p (datum_decl)) > > + { > > + const_tree name = DECL_NAME (datum_decl); > > + if (name && (id_equal (name, "reference_wrapper"))) > > + { > > + /* Retrieve T from std::reference_wrapper<T>, > > + i.e., decltype(datum.get()). */ > > + datum_type = TREE_VEC_ELT (TYPE_TI_ARGS (datum_type), 0); > > + is_refwrap = true; > > + } > > + } > > + } > > + > > + tree datum_expr = build_trait_object (datum_type); > > + tree fn_expr = build_trait_object (fn_type); > > + ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain); > > We should check same-or-base before trying this, not after. > > > + if (error_operand_p (ptrmem_expr) && !is_refwrap) > > + { > > + tree ptrmem_class_type = TYPE_PTRMEM_CLASS_TYPE (fn_type); > > + const bool ptrmem_is_base_of_datum = > > + (NON_UNION_CLASS_TYPE_P (ptrmem_class_type) > > + && NON_UNION_CLASS_TYPE_P (datum_type) > > + && (same_type_ignoring_top_level_qualifiers_p (ptrmem_class_type, > > + datum_type) > > + || DERIVED_FROM_P (ptrmem_class_type, datum_type))); > > + > > + if (!ptrmem_is_base_of_datum) > > + { > > + /* 1.3 & 1.6: Try to dereference datum_expr. */ > > + datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr, > > + RO_UNARY_STAR, NULL_TREE, > > + complain); > > + /* Rebuild ptrmem_expr. */ > > + ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, > > + complain); > > + } > > + } > > + /* 1.1 & 1.4: Otherwise. */ > > + > > + if (error_operand_p (ptrmem_expr)) > > + { > > + if (complain & tf_error) > > + error ("cannot form an INVOKE expression of a pointer to member"); > > if (complain & tf_eror), we should have already given an error, this one > seems redundant. > > Jason > > > + return error_mark_node; > > + } >