tree cplus_expand_constant (tree cst) { switch (TREE_CODE (cst)) { case PTRMEM_CST: { tree type = TREE_TYPE (cst); tree member; /* Find the member. */ member = PTRMEM_CST_MEMBER (cst); /* We can't lower this until the class is complete. */ if (!COMPLETE_TYPE_P (DECL_CONTEXT (member))) return cst; if (TREE_CODE (member) == FIELD_DECL) { /* Find the offset for the field. */ cst = byte_position (member); while (!same_type_p (DECL_CONTEXT (member), TYPE_PTRMEM_CLASS_TYPE (type))) { /* The MEMBER must have been nestled within an anonymous aggregate contained in TYPE. Find the anonymous aggregate. */ member = lookup_anon_field (TYPE_PTRMEM_CLASS_TYPE (type), DECL_CONTEXT (member)); cst = size_binop (PLUS_EXPR, cst, byte_position (member)); } cst = fold (build_nop (type, cst)); } else { tree delta; tree pfn; expand_ptrmemfunc_cst (cst, &delta, &pfn); cst = build_ptrmemfunc1 (type, delta, pfn); } } break; case CONSTRUCTOR: { constructor_elt *elt; unsigned HOST_WIDE_INT idx; FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (cst), idx, elt) elt->value = cplus_expand_constant (elt->value); } default: /* There's nothing to do. */ break; } return cst; }
tree perform_qualification_conversions (tree type, tree expr) { tree expr_type; expr_type = TREE_TYPE (expr); if (same_type_p (type, expr_type)) return expr; else if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type) && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type))) return build_nop (type, expr); else if (TYPE_PTR_TO_MEMBER_P (type) && TYPE_PTR_TO_MEMBER_P (expr_type) && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type), TYPE_PTRMEM_CLASS_TYPE (expr_type)) && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type), TYPE_PTRMEM_POINTED_TO_TYPE (expr_type))) return build_nop (type, expr); else return error_mark_node; }
tree cplus_expand_constant (tree cst) { switch (TREE_CODE (cst)) { case PTRMEM_CST: { tree type = TREE_TYPE (cst); tree member; /* Find the member. */ member = PTRMEM_CST_MEMBER (cst); if (TREE_CODE (member) == FIELD_DECL) { /* Find the offset for the field. */ cst = byte_position (member); while (!same_type_p (DECL_CONTEXT (member), TYPE_PTRMEM_CLASS_TYPE (type))) { /* The MEMBER must have been nestled within an anonymous aggregate contained in TYPE. Find the anonymous aggregate. */ member = lookup_anon_field (TYPE_PTRMEM_CLASS_TYPE (type), DECL_CONTEXT (member)); cst = size_binop (PLUS_EXPR, cst, byte_position (member)); } cst = fold (build_nop (type, cst)); } else { tree delta; tree pfn; expand_ptrmemfunc_cst (cst, &delta, &pfn); cst = build_ptrmemfunc1 (type, delta, pfn); } } break; default: /* There's nothing to do. */ break; } return cst; }
int cxx_types_compatible_p (tree x, tree y) { if (same_type_ignoring_top_level_qualifiers_p (x, y)) return 1; /* Once we get to the middle-end, references and pointers are interchangeable. FIXME should we try to replace all references with pointers? */ if (POINTER_TYPE_P (x) && POINTER_TYPE_P (y) && TYPE_MODE (x) == TYPE_MODE (y) && TYPE_REF_CAN_ALIAS_ALL (x) == TYPE_REF_CAN_ALIAS_ALL (y) && same_type_p (TREE_TYPE (x), TREE_TYPE (y))) return 1; return 0; }
static tree convert_to_pointer_force (tree type, tree expr) { tree intype = TREE_TYPE (expr); enum tree_code form = TREE_CODE (intype); if (form == POINTER_TYPE) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && MAYBE_CLASS_TYPE_P (TREE_TYPE (type)) && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree binfo; binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type), ba_unique, NULL); if (!binfo) { binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_unique, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo) { expr = build_base_path (code, expr, binfo, 0); if (expr == error_mark_node) return error_mark_node; /* Add any qualifier conversions. */ if (!same_type_p (TREE_TYPE (TREE_TYPE (expr)), TREE_TYPE (type))) expr = build_nop (type, expr); return expr; } } } return cp_convert_to_pointer (type, expr); }
int is_friend (tree type, tree supplicant) { int declp; tree list; tree context; if (supplicant == NULL_TREE || type == NULL_TREE) return 0; declp = DECL_P (supplicant); if (declp) /* It's a function decl. */ { tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); tree name = DECL_NAME (supplicant); for (; list ; list = TREE_CHAIN (list)) { if (name == FRIEND_NAME (list)) { tree friends = FRIEND_DECLS (list); for (; friends ; friends = TREE_CHAIN (friends)) { tree this_friend = TREE_VALUE (friends); if (this_friend == NULL_TREE) continue; if (supplicant == this_friend) return 1; if (is_specialization_of_friend (supplicant, this_friend)) return 1; } break; } } } else /* It's a type. */ { if (same_type_p (supplicant, type)) return 1; list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type))); for (; list ; list = TREE_CHAIN (list)) { tree t = TREE_VALUE (list); if (TREE_CODE (t) == TEMPLATE_DECL ? is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) : same_type_p (supplicant, t)) return 1; } } if (declp) { if (DECL_FUNCTION_MEMBER_P (supplicant)) context = DECL_CONTEXT (supplicant); else context = NULL_TREE; } else { if (TYPE_CLASS_SCOPE_P (supplicant)) /* Nested classes get the same access as their enclosing types, as per DR 45 (this is a change from the standard). */ context = TYPE_CONTEXT (supplicant); else /* Local classes have the same access as the enclosing function. */ context = decl_function_context (TYPE_MAIN_DECL (supplicant)); } /* A namespace is not friend to anybody. */ if (context && TREE_CODE (context) == NAMESPACE_DECL) context = NULL_TREE; if (context) return is_friend (type, context); return 0; }
void make_friend_class (tree type, tree friend_type, bool complain) { tree classes; /* CLASS_TEMPLATE_DEPTH counts the number of template headers for the enclosing class. FRIEND_DEPTH counts the number of template headers used for this friend declaration. TEMPLATE_MEMBER_P, defined inside the `if' block for TYPENAME_TYPE case, is true if a template header in FRIEND_DEPTH is intended for DECLARATOR. For example, the code template <class T> struct A { template <class U> struct B { template <class V> template <class W> friend class C<V>::D; }; }; will eventually give the following results 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). 2. FRIEND_DEPTH equals 2 (for `V' and `W'). 3. TEMPLATE_MEMBER_P is true (for `W'). The friend is a template friend iff FRIEND_DEPTH is nonzero. */ int class_template_depth = template_class_depth (type); int friend_depth = processing_template_decl - class_template_depth; if (! MAYBE_CLASS_TYPE_P (friend_type)) { error ("invalid type %qT declared %<friend%>", friend_type); return; } if (friend_depth) /* If the TYPE is a template then it makes sense for it to be friends with itself; this means that each instantiation is friends with all other instantiations. */ { if (CLASS_TYPE_P (friend_type) && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type) && uses_template_parms (friend_type)) { /* [temp.friend] Friend declarations shall not declare partial specializations. */ error ("partial specialization %qT declared %<friend%>", friend_type); return; } } else if (same_type_p (type, friend_type)) { if (complain) warning (0, "class %qT is implicitly friends with itself", type); return; } /* [temp.friend] A friend of a class or class template can be a function or class template, a specialization of a function template or class template, or an ordinary (nontemplate) function or class. */ if (!friend_depth) ;/* ok */ else if (TREE_CODE (friend_type) == TYPENAME_TYPE) { if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type)) == TEMPLATE_ID_EXPR) { /* template <class U> friend class T::X<U>; */ /* [temp.friend] Friend declarations shall not declare partial specializations. */ error ("partial specialization %qT declared %<friend%>", friend_type); return; } else { /* We will figure this out later. */ bool template_member_p = false; tree ctype = TYPE_CONTEXT (friend_type); tree name = TYPE_IDENTIFIER (friend_type); tree decl; if (!uses_template_parms_level (ctype, class_template_depth + friend_depth)) template_member_p = true; if (class_template_depth) { /* We rely on tsubst_friend_class to check the validity of the declaration later. */ if (template_member_p) friend_type = make_unbound_class_template (ctype, name, current_template_parms, tf_error); else friend_type = make_typename_type (ctype, name, class_type, tf_error); } else { decl = lookup_member (ctype, name, 0, true); if (!decl) { error ("%qT is not a member of %qT", name, ctype); return; } if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl)) { error ("%qT is not a member class template of %qT", name, ctype); error ("%q+D declared here", decl); return; } if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL || !CLASS_TYPE_P (TREE_TYPE (decl)))) { error ("%qT is not a nested class of %qT", name, ctype); error ("%q+D declared here", decl); return; } friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)); } } } else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM) { /* template <class T> friend class T; */ error ("template parameter type %qT declared %<friend%>", friend_type); return; } else if (!CLASSTYPE_TEMPLATE_INFO (friend_type)) { /* template <class T> friend class A; where A is not a template */ error ("%q#T is not a template", friend_type); return; } else /* template <class T> friend class A; where A is a template */ friend_type = CLASSTYPE_TI_TEMPLATE (friend_type); if (friend_type == error_mark_node) return; /* See if it is already a friend. */ for (classes = CLASSTYPE_FRIEND_CLASSES (type); classes; classes = TREE_CHAIN (classes)) { tree probe = TREE_VALUE (classes); if (TREE_CODE (friend_type) == TEMPLATE_DECL) { if (friend_type == probe) { if (complain) warning (0, "%qD is already a friend of %qT", probe, type); break; } } else if (TREE_CODE (probe) != TEMPLATE_DECL) { if (same_type_p (probe, friend_type)) { if (complain) warning (0, "%qT is already a friend of %qT", probe, type); break; } } } if (!classes) { maybe_add_class_template_decl_list (type, friend_type, /*friend_p=*/1); CLASSTYPE_FRIEND_CLASSES (type) = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type)); if (TREE_CODE (friend_type) == TEMPLATE_DECL) friend_type = TREE_TYPE (friend_type); if (!uses_template_parms (type)) CLASSTYPE_BEFRIENDING_CLASSES (friend_type) = tree_cons (NULL_TREE, type, CLASSTYPE_BEFRIENDING_CLASSES (friend_type)); } }
static tree cp_convert_to_pointer (tree type, tree expr) { tree intype = TREE_TYPE (expr); enum tree_code form; tree rval; if (intype == error_mark_node) return error_mark_node; if (MAYBE_CLASS_TYPE_P (intype)) { intype = complete_type (intype); if (!COMPLETE_TYPE_P (intype)) { error ("can't convert from incomplete type %qT to %qT", intype, type); return error_mark_node; } rval = build_type_conversion (type, expr); if (rval) { if (rval == error_mark_node) error ("conversion of %qE from %qT to %qT is ambiguous", expr, intype, type); return rval; } } /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) { if (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE) return convert_member_func_to_ptr (type, expr); if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); } if (expr == error_mark_node) return error_mark_node; form = TREE_CODE (intype); if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && MAYBE_CLASS_TYPE_P (TREE_TYPE (type)) && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree binfo; tree intype_class; tree type_class; bool same_p; intype_class = TREE_TYPE (intype); type_class = TREE_TYPE (type); same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class), TYPE_MAIN_VARIANT (type_class)); binfo = NULL_TREE; /* Try derived to base conversion. */ if (!same_p) binfo = lookup_base (intype_class, type_class, ba_check, NULL); if (!same_p && !binfo) { /* Try base to derived conversion. */ binfo = lookup_base (type_class, intype_class, ba_check, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo || same_p) { if (binfo) expr = build_base_path (code, expr, binfo, 0); /* Add any qualifier conversions. */ return build_nop (type, expr); } } if (TYPE_PTRMEMFUNC_P (type)) { error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; } return build_nop (type, expr); } else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))) return convert_ptrmem (type, expr, /*allow_inverse_p=*/false, /*c_cast_p=*/false); else if (TYPE_PTRMEMFUNC_P (intype)) { if (!warn_pmf2ptr) { if (TREE_CODE (expr) == PTRMEM_CST) return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr)); else if (TREE_CODE (expr) == OFFSET_REF) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, TREE_OPERAND (expr, 1)); } } error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; } if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0, /*c_cast_p=*/false); if (TYPE_PTRMEM_P (type)) { /* A NULL pointer-to-member is represented by -1, not by zero. */ expr = build_int_cst_type (type, -1); } else expr = build_int_cst (type, 0); return expr; } else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form)) { error ("invalid conversion from %qT to %qT", intype, type); return error_mark_node; } if (INTEGRAL_CODE_P (form)) { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr); /* Modes may be different but sizes should be the same. There is supposed to be some integral type that is the same width as a pointer. */ gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) == GET_MODE_SIZE (TYPE_MODE (type))); return convert_to_pointer (type, expr); } if (type_unknown_p (expr)) return instantiate_type (type, expr, tf_warning_or_error); error ("cannot convert %qE from type %qT to type %qT", expr, intype, type); return error_mark_node; }
tree ocp_convert (tree type, tree expr, int convtype, int flags) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; if (error_operand_p (e) || type == error_mark_node) return error_mark_node; complete_type (type); complete_type (TREE_TYPE (expr)); if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } e = integral_constant_value (e); if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP)) /* We need a new temporary; don't take this shortcut. */; else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e))) { if (same_type_p (type, TREE_TYPE (e))) /* The call to fold will not always remove the NOP_EXPR as might be expected, since if one of the types is a typedef; the comparison in fold is just equality of pointers, not a call to comptypes. We don't call fold in this case because that can result in infinite recursion; fold will call convert, which will call ocp_convert, etc. */ return e; /* For complex data types, we need to perform componentwise conversion. */ else if (TREE_CODE (type) == COMPLEX_TYPE) return fold_if_not_in_template (convert_to_complex (type, e)); else if (TREE_CODE (e) == TARGET_EXPR) { /* Don't build a NOP_EXPR of class type. Instead, change the type of the temporary. */ TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type; return e; } else { /* We shouldn't be treating objects of ADDRESSABLE type as rvalues. */ gcc_assert (!TREE_ADDRESSABLE (type)); return fold_if_not_in_template (build_nop (type, e)); } } if (code == VOID_TYPE && (convtype & CONV_STATIC)) { e = convert_to_void (e, /*implicit=*/NULL, tf_warning_or_error); return e; } if (INTEGRAL_CODE_P (code)) { tree intype = TREE_TYPE (e); if (TREE_CODE (type) == ENUMERAL_TYPE) { /* enum = enum, enum = int, enum = float, (enum)pointer are all errors. */ if (((INTEGRAL_OR_ENUMERATION_TYPE_P (intype) || TREE_CODE (intype) == REAL_TYPE) && ! (convtype & CONV_STATIC)) || TREE_CODE (intype) == POINTER_TYPE) { if (flags & LOOKUP_COMPLAIN) permerror (input_location, "conversion from %q#T to %q#T", intype, type); if (!flag_permissive) return error_mark_node; } /* [expr.static.cast] 8. A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values. Otherwise, the resulting enumeration value is unspecified. */ if (TREE_CODE (expr) == INTEGER_CST && !int_fits_type_p (expr, type)) warning (OPT_Wconversion, "the result of the conversion is unspecified because " "%qE is outside the range of type %qT", expr, type); } if (MAYBE_CLASS_TYPE_P (intype)) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; if (flags & LOOKUP_COMPLAIN) error ("%q#T used where a %qT was expected", intype, type); return error_mark_node; } if (code == BOOLEAN_TYPE) return cp_truthvalue_conversion (e); return fold_if_not_in_template (convert_to_integer (type, e)); } if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type)) return fold_if_not_in_template (cp_convert_to_pointer (type, e)); if (code == VECTOR_TYPE) { tree in_vtype = TREE_TYPE (e); if (MAYBE_CLASS_TYPE_P (in_vtype)) { tree ret_val; ret_val = build_type_conversion (type, e); if (ret_val) return ret_val; if (flags & LOOKUP_COMPLAIN) error ("%q#T used where a %qT was expected", in_vtype, type); return error_mark_node; } return fold_if_not_in_template (convert_to_vector (type, e)); } if (code == REAL_TYPE || code == COMPLEX_TYPE) { if (MAYBE_CLASS_TYPE_P (TREE_TYPE (e))) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; else if (flags & LOOKUP_COMPLAIN) error ("%q#T used where a floating point value was expected", TREE_TYPE (e)); } if (code == REAL_TYPE) return fold_if_not_in_template (convert_to_real (type, e)); else if (code == COMPLEX_TYPE) return fold_if_not_in_template (convert_to_complex (type, e)); } /* New C++ semantics: since assignment is now based on memberwise copying, if the rhs type is derived from the lhs type, then we may still do a conversion. */ if (RECORD_OR_UNION_CODE_P (code)) { tree dtype = TREE_TYPE (e); tree ctor = NULL_TREE; dtype = TYPE_MAIN_VARIANT (dtype); /* Conversion between aggregate types. New C++ semantics allow objects of derived type to be cast to objects of base type. Old semantics only allowed this between pointers. There may be some ambiguity between using a constructor vs. using a type conversion operator when both apply. */ ctor = e; if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; if (BRACE_ENCLOSED_INITIALIZER_P (ctor)) ctor = perform_implicit_conversion (type, ctor, tf_warning_or_error); else if ((flags & LOOKUP_ONLYCONVERTING) && ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype))) /* For copy-initialization, first we create a temp of the proper type with a user-defined conversion sequence, then we direct-initialize the target with the temp (see [dcl.init]). */ ctor = build_user_type_conversion (type, ctor, flags); else ctor = build_special_member_call (NULL_TREE, complete_ctor_identifier, build_tree_list (NULL_TREE, ctor), type, flags, tf_warning_or_error); if (ctor) return build_cplus_new (type, ctor); } if (flags & LOOKUP_COMPLAIN) error ("conversion from %qT to non-scalar type %qT requested", TREE_TYPE (expr), type); return error_mark_node; }
static tree cp_convert_to_pointer (tree type, tree expr, bool force) { tree intype = TREE_TYPE (expr); enum tree_code form; tree rval; if (intype == error_mark_node) return error_mark_node; if (IS_AGGR_TYPE (intype)) { intype = complete_type (intype); if (!COMPLETE_TYPE_P (intype)) { error ("can't convert from incomplete type `%T' to `%T'", intype, type); return error_mark_node; } rval = build_type_conversion (type, expr); if (rval) { if (rval == error_mark_node) error ("conversion of `%E' from `%T' to `%T' is ambiguous", expr, intype, type); return rval; } } /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */ if (TREE_CODE (type) == POINTER_TYPE && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) { /* Allow an implicit this pointer for pointer to member functions. */ if (TYPE_PTRMEMFUNC_P (intype)) { if (pedantic || warn_pmf2ptr) pedwarn ("converting from `%T' to `%T'", intype, type); if (TREE_CODE (expr) == PTRMEM_CST) expr = build_address (PTRMEM_CST_MEMBER (expr)); else { tree decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0); decl = build_address (decl); expr = get_member_function_from_ptrfunc (&decl, expr); } } else if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE) { if (pedantic || warn_pmf2ptr) pedwarn ("converting from `%T' to `%T'", intype, type); expr = build_addr_func (expr); } if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); } if (expr == error_mark_node) return error_mark_node; form = TREE_CODE (intype); if (POINTER_TYPE_P (intype)) { intype = TYPE_MAIN_VARIANT (intype); if (TYPE_MAIN_VARIANT (type) != intype && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE && IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE) { enum tree_code code = PLUS_EXPR; tree binfo; tree intype_class; tree type_class; bool same_p; intype_class = TREE_TYPE (intype); type_class = TREE_TYPE (type); same_p = same_type_p (TYPE_MAIN_VARIANT (intype_class), TYPE_MAIN_VARIANT (type_class)); binfo = NULL_TREE; /* Try derived to base conversion. */ if (!same_p) binfo = lookup_base (intype_class, type_class, ba_check, NULL); if (!same_p && !binfo) { /* Try base to derived conversion. */ binfo = lookup_base (type_class, intype_class, ba_check, NULL); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (binfo || same_p) { if (binfo) expr = build_base_path (code, expr, binfo, 0); /* Add any qualifier conversions. */ return build_nop (type, expr); } } if (TYPE_PTRMEMFUNC_P (type)) { error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; } return build_nop (type, expr); } else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) { tree b1; tree b2; tree binfo; enum tree_code code = PLUS_EXPR; base_kind bk; b1 = TYPE_PTRMEM_CLASS_TYPE (type); b2 = TYPE_PTRMEM_CLASS_TYPE (intype); binfo = lookup_base (b1, b2, ba_check, &bk); if (!binfo) { binfo = lookup_base (b2, b1, ba_check, &bk); code = MINUS_EXPR; } if (binfo == error_mark_node) return error_mark_node; if (bk == bk_via_virtual) { if (force) warning ("pointer to member cast from `%T' to `%T' is via virtual base", intype, type); else { error ("pointer to member cast from `%T' to `%T' is via virtual base", intype, type); return error_mark_node; } /* This is a reinterpret cast, whose result is unspecified. We choose to do nothing. */ return build1 (NOP_EXPR, type, expr); } if (TREE_CODE (expr) == PTRMEM_CST) expr = cplus_expand_constant (expr); if (binfo && !integer_zerop (BINFO_OFFSET (binfo))) expr = size_binop (code, build_nop (sizetype, expr), BINFO_OFFSET (binfo)); return build_nop (type, expr); } else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); else if (TYPE_PTRMEMFUNC_P (intype)) { if (!warn_pmf2ptr) { if (TREE_CODE (expr) == PTRMEM_CST) return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr), force); else if (TREE_CODE (expr) == OFFSET_REF) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, TREE_OPERAND (expr, 1)); } } error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; } if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); if (TYPE_PTRMEM_P (type)) /* A NULL pointer-to-member is represented by -1, not by zero. */ expr = build_int_2 (-1, -1); else expr = build_int_2 (0, 0); TREE_TYPE (expr) = type; /* Fix up the representation of -1 if appropriate. */ force_fit_type (expr, 0); return expr; } else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form)) { error ("invalid conversion from '%T' to '%T'", intype, type); return error_mark_node; } if (INTEGRAL_CODE_P (form)) { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr); /* Modes may be different but sizes should be the same. */ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) != GET_MODE_SIZE (TYPE_MODE (type))) /* There is supposed to be some integral type that is the same width as a pointer. */ abort (); return convert_to_pointer (type, expr); } if (type_unknown_p (expr)) return instantiate_type (type, expr, tf_error | tf_warning); error ("cannot convert `%E' from type `%T' to type `%T'", expr, intype, type); return error_mark_node; }
tree ocp_convert (tree type, tree expr, int convtype, int flags) { tree e = expr; enum tree_code code = TREE_CODE (type); if (error_operand_p (e) || type == error_mark_node) return error_mark_node; complete_type (type); complete_type (TREE_TYPE (expr)); e = decl_constant_value (e); if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP) /* Some internal structures (vtable_entry_type, sigtbl_ptr_type) don't go through finish_struct, so they don't have the synthesized constructors. So don't force a temporary. */ && TYPE_HAS_CONSTRUCTOR (type)) /* We need a new temporary; don't take this shortcut. */; else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))) { if (same_type_p (type, TREE_TYPE (e))) /* The call to fold will not always remove the NOP_EXPR as might be expected, since if one of the types is a typedef; the comparison in fold is just equality of pointers, not a call to comptypes. We don't call fold in this case because that can result in infinite recursion; fold will call convert, which will call ocp_convert, etc. */ return e; /* For complex data types, we need to perform componentwise conversion. */ else if (TREE_CODE (type) == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); else if (TREE_CODE (e) == TARGET_EXPR) { /* Don't build a NOP_EXPR of class type. Instead, change the type of the temporary. Only allow this for cv-qual changes, though. */ if (!same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)), TYPE_MAIN_VARIANT (type))) abort (); TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type; return e; } else if (TREE_ADDRESSABLE (type)) /* We shouldn't be treating objects of ADDRESSABLE type as rvalues. */ abort (); else return fold (build1 (NOP_EXPR, type, e)); } if (code == VOID_TYPE && (convtype & CONV_STATIC)) { e = convert_to_void (e, /*implicit=*/NULL); return e; } if (INTEGRAL_CODE_P (code)) { tree intype = TREE_TYPE (e); /* enum = enum, enum = int, enum = float, (enum)pointer are all errors. */ if (TREE_CODE (type) == ENUMERAL_TYPE && ((ARITHMETIC_TYPE_P (intype) && ! (convtype & CONV_STATIC)) || (TREE_CODE (intype) == POINTER_TYPE))) { pedwarn ("conversion from `%#T' to `%#T'", intype, type); if (flag_pedantic_errors) return error_mark_node; } if (IS_AGGR_TYPE (intype)) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; if (flags & LOOKUP_COMPLAIN) error ("`%#T' used where a `%T' was expected", intype, type); if (flags & LOOKUP_SPECULATIVELY) return NULL_TREE; return error_mark_node; } if (code == BOOLEAN_TYPE) return cp_truthvalue_conversion (e); return fold (convert_to_integer (type, e)); } if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type)) return fold (cp_convert_to_pointer (type, e, false)); if (code == VECTOR_TYPE) return fold (convert_to_vector (type, e)); if (code == REAL_TYPE || code == COMPLEX_TYPE) { if (IS_AGGR_TYPE (TREE_TYPE (e))) { tree rval; rval = build_type_conversion (type, e); if (rval) return rval; else if (flags & LOOKUP_COMPLAIN) error ("`%#T' used where a floating point value was expected", TREE_TYPE (e)); } if (code == REAL_TYPE) return fold (convert_to_real (type, e)); else if (code == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); } /* New C++ semantics: since assignment is now based on memberwise copying, if the rhs type is derived from the lhs type, then we may still do a conversion. */ if (IS_AGGR_TYPE_CODE (code)) { tree dtype = TREE_TYPE (e); tree ctor = NULL_TREE; dtype = TYPE_MAIN_VARIANT (dtype); /* Conversion between aggregate types. New C++ semantics allow objects of derived type to be cast to objects of base type. Old semantics only allowed this between pointers. There may be some ambiguity between using a constructor vs. using a type conversion operator when both apply. */ ctor = e; if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; if ((flags & LOOKUP_ONLYCONVERTING) && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype))) /* For copy-initialization, first we create a temp of the proper type with a user-defined conversion sequence, then we direct-initialize the target with the temp (see [dcl.init]). */ ctor = build_user_type_conversion (type, ctor, flags); else ctor = build_special_member_call (NULL_TREE, complete_ctor_identifier, build_tree_list (NULL_TREE, ctor), TYPE_BINFO (type), flags); if (ctor) return build_cplus_new (type, ctor); } if (flags & LOOKUP_COMPLAIN) error ("conversion from `%T' to non-scalar type `%T' requested", TREE_TYPE (expr), type); if (flags & LOOKUP_SPECULATIVELY) return NULL_TREE; return error_mark_node; }
void make_friend_class (tree type, tree friend_type, bool complain) { tree classes; /* CLASS_TEMPLATE_DEPTH counts the number of template headers for the enclosing class. FRIEND_DEPTH counts the number of template headers used for this friend declaration. TEMPLATE_MEMBER_P, defined inside the `if' block for TYPENAME_TYPE case, is true if a template header in FRIEND_DEPTH is intended for DECLARATOR. For example, the code template <class T> struct A { template <class U> struct B { template <class V> template <class W> friend class C<V>::D; }; }; will eventually give the following results 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). 2. FRIEND_DEPTH equals 2 (for `V' and `W'). 3. TEMPLATE_MEMBER_P is true (for `W'). The friend is a template friend iff FRIEND_DEPTH is nonzero. */ int class_template_depth = template_class_depth (type); int friend_depth = processing_template_decl - class_template_depth; if (! MAYBE_CLASS_TYPE_P (friend_type) && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM) { /* N1791: If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the friend declaration is ignored. So don't complain in C++11 mode. */ if (cxx_dialect < cxx11) pedwarn (input_location, complain ? 0 : OPT_Wpedantic, "invalid type %qT declared %<friend%>", friend_type); return; } friend_type = cv_unqualified (friend_type); if (check_for_bare_parameter_packs (friend_type)) return; if (friend_depth) { /* [temp.friend] Friend declarations shall not declare partial specializations. */ if (CLASS_TYPE_P (friend_type) && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type) && uses_template_parms (friend_type)) { error ("partial specialization %qT declared %<friend%>", friend_type); return; } if (TYPE_TEMPLATE_INFO (friend_type) && !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type))) { error ("%qT is not a template", friend_type); inform (location_of (friend_type), "previous declaration here"); if (TYPE_CLASS_SCOPE_P (friend_type) && CLASSTYPE_TEMPLATE_INFO (TYPE_CONTEXT (friend_type)) && currently_open_class (TYPE_CONTEXT (friend_type))) inform (input_location, "perhaps you need explicit template " "arguments in your nested-name-specifier"); return; } } /* It makes sense for a template class to be friends with itself, that means the instantiations can be friendly. Other cases are not so meaningful. */ if (!friend_depth && same_type_p (type, friend_type)) { if (complain) warning (0, "class %qT is implicitly friends with itself", type); return; } /* [temp.friend] A friend of a class or class template can be a function or class template, a specialization of a function template or class template, or an ordinary (nontemplate) function or class. */ if (!friend_depth) ;/* ok */ else if (TREE_CODE (friend_type) == TYPENAME_TYPE) { if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type)) == TEMPLATE_ID_EXPR) { /* template <class U> friend class T::X<U>; */ /* [temp.friend] Friend declarations shall not declare partial specializations. */ error ("partial specialization %qT declared %<friend%>", friend_type); return; } else { /* We will figure this out later. */ bool template_member_p = false; tree ctype = TYPE_CONTEXT (friend_type); tree name = TYPE_IDENTIFIER (friend_type); tree decl; if (!uses_template_parms_level (ctype, class_template_depth + friend_depth)) template_member_p = true; if (class_template_depth) { /* We rely on tsubst_friend_class to check the validity of the declaration later. */ if (template_member_p) friend_type = make_unbound_class_template (ctype, name, current_template_parms, tf_error); else friend_type = make_typename_type (ctype, name, class_type, tf_error); } else { decl = lookup_member (ctype, name, 0, true, tf_warning_or_error); if (!decl) { error ("%qT is not a member of %qT", name, ctype); return; } if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl)) { error ("%qT is not a member class template of %qT", name, ctype); inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); return; } if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL || !CLASS_TYPE_P (TREE_TYPE (decl)))) { error ("%qT is not a nested class of %qT", name, ctype); inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl); return; } friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)); } } } else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM) { /* template <class T> friend class T; */ error ("template parameter type %qT declared %<friend%>", friend_type); return; } else if (TREE_CODE (friend_type) == TEMPLATE_TEMPLATE_PARM) friend_type = TYPE_NAME (friend_type); else if (!CLASSTYPE_TEMPLATE_INFO (friend_type)) { /* template <class T> friend class A; where A is not a template */ error ("%q#T is not a template", friend_type); return; } else /* template <class T> friend class A; where A is a template */ friend_type = CLASSTYPE_TI_TEMPLATE (friend_type); if (friend_type == error_mark_node) return; /* See if it is already a friend. */ for (classes = CLASSTYPE_FRIEND_CLASSES (type); classes; classes = TREE_CHAIN (classes)) { tree probe = TREE_VALUE (classes); if (TREE_CODE (friend_type) == TEMPLATE_DECL) { if (friend_type == probe) { if (complain) warning (OPT_Wredundant_decls, "%qD is already a friend of %qT", probe, type); break; } } else if (TREE_CODE (probe) != TEMPLATE_DECL) { if (same_type_p (probe, friend_type)) { if (complain) warning (OPT_Wredundant_decls, "%qT is already a friend of %qT", probe, type); break; } } } if (!classes) { maybe_add_class_template_decl_list (type, friend_type, /*friend_p=*/1); CLASSTYPE_FRIEND_CLASSES (type) = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type)); if (TREE_CODE (friend_type) == TEMPLATE_DECL) friend_type = TREE_TYPE (friend_type); if (!uses_template_parms (type)) CLASSTYPE_BEFRIENDING_CLASSES (friend_type) = tree_cons (NULL_TREE, type, CLASSTYPE_BEFRIENDING_CLASSES (friend_type)); } }