/** * \file implicit_conversion.cpp * \brief Generate Implicit Conversions * \author Stefan Reuther * * This module generates implicit conversion sequences, as set out * in chapter 13. */ INTERFACE: #include #include #include "expr_result.h" #include "garbage.h" class Function_signature; typedef std::map Conversion_op_map; struct ICS_Types { /** Actions that can be done in an ICS step. */ enum Action { a_NullStep, /* table 9 in 13.3.3.1.1 */ a_LValueToRValue, a_ArrayToPointer, a_FunctionToPointer, a_QualificationAdjustment, a_IntegralPromotion, a_FloatingPromotion, a_IntegralConversion, a_FloatingConversion, a_FloatingIntegralConversion, a_PointerConversion, a_PtrMemConversion, a_BoolConversion, a_DerivedToBaseConversion, /* user-defined ICS */ a_CtorCall, a_ConversionOp, a_Ellipsis, a_BindReferenceToTemporary // a_OverloadResolution }; /** Forms of an ICS. */ enum Form { f_NoForm, // used by steps which don't affect the form f_Standard, f_Userdef, f_Ellipsis }; /** Ranks of an ICS. */ enum Rank { r_NoRank, // used by steps which don't affect the rank r_Exact, r_Promotion, r_Conversion }; /** Comparing two ICSs. These are parameters to Implicit_conversion::is_better_than(). */ enum Compare { /** Compare the ICSs according to the normal ordering rules. This one's used for overload resolutions. */ c_CompareAll, /** Compare the ICSs only after the user-defined conversion. This one is used when we initialize a non-class type with a class, so that we pick the best target type (13.3.1.5). */ c_CompareWithInitRules, /** Compare the ICSs only before the user-defined conversion. This is used when we copy-initialize a class with a non-matching type, so that we pick the best constructor (13.3.1.4). */ c_CompareBeforeUserConversion }; typedef Expr_result::Kind Kind; }; struct ICS_Step : ICS_Types { Type type; Kind kind; Function_signature* function; Action action; ICS_Step(Type type, Kind kind, Action action) : type(type), kind(kind), function(0), action(action) { } ICS_Step(Type type, Kind kind, Function_signature* function, Action action) : type(type), kind(kind), function(function), action(action) { } }; class Implicit_conversion : public ICS_Types, public virtual G_cleanup { public: typedef ICS_Step Step; typedef std::vector Step_vec; private: Step_vec steps; std::string warnings; bool maybe_npc; /* status */ Form form; Rank rank; bool ambiguous; public: Form get_form() const { return form; } Rank get_rank() const { return rank; } bool is_ambiguous() const { return ambiguous; } void set_ambiguous() { ambiguous = true; } }; IMPLEMENTATION: #include #include "except.h" #include "symbol_table.h" #include "function.h" #include "class.h" #include "annotation.h" #include "downcast.h" #include "symbol_name.h" /************************** Implicit_conversion **************************/ /** \class Implicit_conversion \brief Implicit Conversion Sequence (ICS) Every ICS starts with a null step (a_NullStep) followed by any number of conversion steps. Each step contains the target type of its conversion, the source type for that step is the target of the previous one (that's what the null step is for). The first step may contain a Function_signature pointer in its /function/ member, when the expression to convert is an overloaded function. */ /** Make an implicit conversion sequence starting at /result/. */ PUBLIC Implicit_conversion::Implicit_conversion(const Expr_result& result, Function_signature* symbol_hint) : form(f_Standard), rank(r_Exact), ambiguous(false) { steps.push_back(Step(result.get_type(), result.get_kind(), symbol_hint, a_NullStep)); maybe_npc = result.is_npc(); assert(result.is_value()); } PUBLIC Implicit_conversion::~Implicit_conversion() { } /** Get current final step. This one contains the current type. */ PUBLIC inline const Implicit_conversion::Step& Implicit_conversion::get_current() { return steps.back(); } /** True iff the initial expression is a possible null pointer constant. */ PUBLIC inline bool Implicit_conversion::is_npc() const { return maybe_npc; } /** Ensure that a warning is displayed when this ICS is used. */ PUBLIC void Implicit_conversion::warn_if_used(std::string s) { if (warnings.length()) warnings += "\nwarning: "; warnings += s; } /** Add a step. */ PUBLIC void Implicit_conversion::add_step(Step s) { // maybe validate the step here Form f = s.get_form(); if (f > form) form = f; Rank r = s.get_rank(); if (r > rank) rank = r; steps.push_back(s); } /** Add conversion to a type. Conversions don't change lvalueness etc. */ PUBLIC void Implicit_conversion::add_conversion(Action a, Type t) { assert(get_current().type != t); add_step(Step(t, get_current().kind, a)); } /** Convert to lvalue, and add qualifiers. This also applies the array-to-pointer and function-to-pointer conversions. */ PUBLIC bool Implicit_conversion::convert_to_rvalue(Type target) { Type t = get_current().type; if (t.get_kind() == Type::k_Array) add_step(Step(t.get_basis_type().make_pointer_type(), Expr_result::k_RValue, a_ArrayToPointer)); else if (t.get_kind() == Type::k_Function) add_step(Step(t.make_pointer_type(), Expr_result::k_RValue, a_FunctionToPointer)); else if (get_current().kind != Expr_result::k_RValue) { if (!t.is_class_type()) t = t.get_unqualified_type(); add_step(Step(t, Expr_result::k_RValue, a_LValueToRValue)); } else if (!t.is_class_type()) { Type t2 = t.get_unqualified_type().with_qualifiers(target); if (t2 != t) add_step(Step(t2, Expr_result::k_RValue, a_QualificationAdjustment)); } t = get_current().type; if (t.is_class_type()) { if (target.is_more_qualified_than(t)) { t.copy_qualifiers(target); add_step(Step(t, Expr_result::k_RValue, a_QualificationAdjustment)); return true; } else if (t.is_more_qualified_than(target)) { /* no way */ return false; } else { return true; } } else return true; } /** Display this ICS on /os/. */ PUBLIC void Implicit_conversion::dump(std::ostream& os) { for (Step_vec::iterator i = steps.begin(); i != steps.end(); ++i) { os << ". "; i->dump(os); os << '\n'; } } PUBLIC bool Implicit_conversion::uses_temporary() const { for (Step_vec::const_iterator i = steps.begin(); i != steps.end(); ++i) if (i->action == a_BindReferenceToTemporary) return true; return false; } /** True iff p is a conversion of a pointer to bool. */ static inline bool is_ptr_to_bool(Implicit_conversion::Step_vec::const_iterator p) { return p->action == Implicit_conversion::a_BoolConversion && (p[-1].type.get_kind() == Type::k_Pointer || p[-1].type.get_kind() == Type::k_Member); } static Class_symbol* class_or_null(const Type& t) { if (t.get_kind() == Type::k_Userdef) return dynamic_cast(t.get_type_symbol()); else return 0; } /** Compare two standard conversion sequences. Returns true iff [a1,e1) is better than [a2,e2) according to the rules in 13.3.3.2. */ PRIVATE static bool Implicit_conversion::scs_is_better_than(Step_vec::const_iterator a1, Step_vec::const_iterator e1, Step_vec::const_iterator a2, Step_vec::const_iterator e2) { /* skip LValue transformations */ if (a1 != e1 && (a1->action == a_NullStep || a1->is_lvalue_transformation())) ++a1; if (a2 != e2 && (a2->action == a_NullStep || a2->is_lvalue_transformation())) ++a2; /* sub-sequence rule. Looking at gcc, there's quite a lot of optimisation potential for this step. */ if (e1 - a1 < e2 - a2 && std::search(a2, e2, a1, e1) != e2) return true; /* rank rule */ Rank r1 = r_Exact, r2 = r_Exact; for (Step_vec::const_iterator i = a1; i != e1; ++i) if (i->get_rank() > r1) r1 = i->get_rank(); for (Step_vec::const_iterator i = a2; i != e2; ++i) if (i->get_rank() > r2) r2 = i->get_rank(); if (r1 < r2) return true; if (r1 == r2 && r1 != r_Exact) { /* point p1 and p2 to the interesting step. The relevant ranks are worse than r_Exact */ Step_vec::const_iterator p1 = a1, p2 = a2; while (p1->get_rank() == r_Exact) ++p1; while (p2->get_rank() == r_Exact) ++p2; /* ptr->bool or PM->bool is worse than others */ // 0 if neither or both are ptr->bool // 1 if p2 is ptr->bool and p1 is not, i.e. p1 is better // -1 if p1 is ptr->bool and p1 is not int result = is_ptr_to_bool(p2) - is_ptr_to_bool(p1); if (result) return result > 0; if (p1->action == p2->action) { if (p1->action == a_PointerConversion) { // Pointer conversion. Source type might be NPC or pointer. Type src1 = p1[-1].type, src2 = p2[-1].type, dest1 = p1[0].type.get_basis_type(), dest2 = p2[0].type.get_basis_type(); if (src1.get_kind() == Type::k_Pointer && src2.get_kind() == Type::k_Pointer) { src1 = src1.get_basis_type(); src2 = src2.get_basis_type(); Class_symbol *sclass1 = class_or_null(src1), *sclass2 = class_or_null(src2), *dclass1 = class_or_null(dest1), *dclass2 = class_or_null(dest2); if (dest1.is_void() && dest2.is_void()) { // Base*->void* better than Der*->void* if (sclass1 && sclass2 && sclass1->is_base_class_of(sclass2)) return true; } else if (dest2.is_void()) { // Der*->Base* better than Der*->void* assert(dclass1->is_base_class_of(sclass1)); if (sclass1 && dclass1 && sclass1==sclass2) return true; } else if (sclass1 && dclass1 && sclass2 && dclass2) { // C*->B* better than C*->A* if (sclass1 == sclass2 && dclass2->is_base_class_of(dclass1)) return true; // B*->A* better than C*->A* if (dclass1 == dclass2 && sclass1->is_base_class_of(sclass2)) return true; } } } else if (p1->action == a_PtrMemConversion) { Type src1 = p1[-1].type, src2 = p2[-1].type; if (src1.get_kind() == Type::k_Member && src2.get_kind() == Type::k_Member) { Class_symbol *sclass1 = class_or_null(src1), *sclass2 = class_or_null(src2), *dclass1 = class_or_null(p1[0].type.get_class_type()), *dclass2 = class_or_null(p2[0].type.get_class_type()); assert(sclass1); assert(sclass2); assert(dclass1); assert(dclass2); if (sclass1 == sclass2 && dclass1->is_base_class_of(dclass2)) // A::*->B::* better than A::*->C::* return true; if (dclass1 == dclass2 && sclass2->is_base_class_of(sclass1)) // B::*->C::* better than A::*->C::* return true; } } else if (p1->action == a_DerivedToBaseConversion) { // C&->B& better than C&->A& // B&->A& better than C&->A& // B->A better than C->A Class_symbol *sclass1 = class_or_null(p1[-1].type), *sclass2 = class_or_null(p2[-1].type), *dclass1 = class_or_null(p1[0].type), *dclass2 = class_or_null(p2[0].type); assert(sclass1); assert(sclass2); assert(dclass1); assert(dclass2); if (sclass1 == sclass2 && dclass2->is_base_class_of(dclass1)) return true; if (dclass1 == dclass2 && sclass1->is_base_class_of(sclass2)) return true; } } } /* qualification conversion rule */ // FIXME /* reference binding rule */ // FIXME return false; } /** True iff this ICS is better than /other/. \param is_initialisation true iff this is an initialisation, i.e. compare conversion operator calls according to 13.3.3. False iff this is normal overload resolution. \return true if this ICS is better, false if it is worse or incomparable. */ PUBLIC bool Implicit_conversion::is_better_than(Implicit_conversion* other, Compare comparison_type) { /* Compare basic forms, 13.3.3.2p2 */ if (get_form() < other->get_form()) return true; if (get_form() > other->get_form()) return false; /* Two standard conversion sequences */ if (get_form() == f_Standard) { return scs_is_better_than(steps.begin(), steps.end(), other->steps.begin(), other->steps.end()); } else if (get_form() == f_Userdef) { Step_vec::const_iterator hit = steps.end(); while (hit != steps.begin() && (--hit)->get_form() != f_Userdef) ; Step_vec::const_iterator oit = other->steps.end(); while (oit != other->steps.begin() && (--oit)->get_form() != f_Userdef) ; /* hit, oit now point at the user-defined step */ assert(hit != steps.end()); assert(oit != other->steps.end()); /* 13.3.1.4: we're comparing the sequence *before* the user converter */ if (comparison_type == c_CompareBeforeUserConversion) { return scs_is_better_than(steps.begin(), hit, other->steps.begin(), oit); } /* 13.3.3.2p3, 13.3.1.5 */ if (comparison_type == c_CompareWithInitRules && hit->action == Implicit_conversion::a_ConversionOp && oit->action == Implicit_conversion::a_ConversionOp) { /* it is an initialisation by user-defined conversion operator. This makes sure that for struct a { operator int(); operator void*(); } the_a; bool b = the_a; the "int" operator is chosen. */ } else { /* normal overload resolution. 13.3.3.2p3 says that two UCS's using different functions are indistinguishable. This makes void foo(int); void foo(void*); // ... foo(the_a); ambiguous but void qoo(int); void qoo(short); qoo(the_a) work. */ if (hit->function != oit->function) return false; } return scs_is_better_than(++hit, steps.end(), ++oit, other->steps.end()); } return false; } /** Called before this implicit conversion is used. Displays warnings, and bombs out if this use is not allowed. */ PUBLIC Expr_result Implicit_conversion::make_tree(Expr_result expr) { if (is_ambiguous()) compile_error("conversion from `" + steps.front().type.get_human_readable_type() + "' to `" + steps.back().type.get_human_readable_type() + "' is ambiguous"); if (warnings.length()) compile_warning(warnings, expr.get_tree()); /* first, annotate the expr tree */ if (expr.is_function()) { assert(steps.front().function); fill_in_overload_annotation(expr.get_tree(), steps.front().function, steps.front().type); expr.set_value(expr.get_tree(), steps.front().type); } /* process the expression */ for (Step_vec::iterator i = steps.begin()+1; i != steps.end(); ++i) { switch (i->action) { case a_NullStep: assert(0); case a_QualificationAdjustment: break; // this one's purely conceptual with no effect on the semantics. case a_LValueToRValue: case a_ArrayToPointer: case a_FunctionToPointer: case a_IntegralPromotion: case a_FloatingPromotion: case a_IntegralConversion: case a_FloatingConversion: case a_FloatingIntegralConversion: case a_PointerConversion: case a_PtrMemConversion: case a_BoolConversion: case a_DerivedToBaseConversion: /* I guess not all these actually need a cast, but why not. */ expr.set_value(make_cast_expr_unchecked(expr.get_tree(), i->type), i->type); expr.set_kind(i->kind); break; case a_CtorCall: /* constructor call. Note that the type differs from the type encoded into the actual constructor symbol: constructors have type "function taking returning nothing", but when called, they have type "function taking returning " */ assert(i->function); expr.set_value(make_unary_funcall(make_name(i->function), i->type, expr.get_tree()), i->type); expr.set_kind(i->kind); break; case a_ConversionOp: /* conversion operator. These have type "function taking returning " whereas they appear in symbol tables as "member function taking returning " */ assert(i->function); expr.set_value(make_unary_funcall(make_name(i->function), i->type, expr.get_tree()), i->type); expr.set_kind(i->kind); break; case a_Ellipsis: /* this one's purely conceptual. */ break; case a_BindReferenceToTemporary: /* FIXME: what to do with this one? */ break; } } return expr; } /** Assuming this is a reference, convert it to "reference to target". Return false if impossible. */ PUBLIC bool Implicit_conversion::convert_reference(Type target) { Type ics_type = get_current().type; if (!ics_type.is_same_unqualified_type(target)) { /* not same type -- must be derived class */ if (ics_type.get_kind() != Type::k_Userdef || target.get_kind() != Type::k_Userdef) return false; Class_symbol* sclass = dynamic_cast(ics_type.get_type_symbol()); Class_symbol* tclass = dynamic_cast(target.get_type_symbol()); if (!sclass || !tclass || !tclass->is_base_class_of(sclass)) return false; /* derived-to-base conversion */ ics_type = target.get_unqualified_type().with_qualifiers(ics_type); add_conversion(a_DerivedToBaseConversion, ics_type); } if (ics_type.is_more_qualified_than(target)) return false; if (target.is_more_qualified_than(ics_type)) add_conversion(a_QualificationAdjustment, target); return true; } PUBLIC void Implicit_conversion::append_from(Implicit_conversion* other) { assert(steps.back().type == other->steps.front().type); assert(steps.back().kind == other->steps.front().kind); assert(other->steps.front().action == a_NullStep); for (Step_vec::const_iterator i = other->steps.begin()+1; i != other->steps.end(); ++i) add_step(*i); if (other->is_ambiguous()) set_ambiguous(); } /*********************** Implicit_conversion::Step ***********************/ bool operator==(const ICS_Step& lhs, const ICS_Step& rhs) { return lhs.type == rhs.type && lhs.kind == rhs.kind && lhs.function == rhs.function && lhs.action == rhs.action; } /** Get rank of a conversion step (13.3.3.1.1). The rank of the whole sequence is max(rank(step)). */ PUBLIC ICS_Step::Rank ICS_Step::get_rank() const { switch (action) { default: return r_NoRank; case a_LValueToRValue: case a_ArrayToPointer: case a_FunctionToPointer: case a_QualificationAdjustment: return r_Exact; case a_IntegralPromotion: case a_FloatingPromotion: return r_Promotion; case a_IntegralConversion: case a_FloatingConversion: case a_FloatingIntegralConversion: case a_PointerConversion: case a_PtrMemConversion: case a_BoolConversion: case a_DerivedToBaseConversion: return r_Conversion; } } /** Get form of a conversion step (13.3.3.1). The form of the whole sequence is max(form(step)). */ PUBLIC ICS_Step::Form ICS_Step::get_form() const { switch (action) { case a_NullStep: return f_NoForm; default: return f_Standard; case a_CtorCall: case a_ConversionOp: return f_Userdef; case a_Ellipsis: return f_Ellipsis; case a_BindReferenceToTemporary: // case a_OverloadResolution: return f_NoForm; } } PUBLIC /*inline*/ bool ICS_Step::is_lvalue_transformation() const { return (action == a_LValueToRValue || action == a_ArrayToPointer || action == a_FunctionToPointer); } /** Get name of the action in this step. */ const char* ICS_Step::get_action_name() const { static const char*const names[] = { "null", "lvalue->rvalue", "array->pointer", "function->pointer", "qualification adjustment", "integral promotion", "fp promotion", "integral conversion", "fp conversion", "fp/integral conversion", "pointer conversion", "member pointer conversion", "anything->bool conversion", "derived->base conversion", "constructor call", "conversion operator", "ellipsis conversion", "bind reference to temporary", // "overload resolution" }; return names[action]; } PUBLIC void ICS_Step::dump(std::ostream& os) const { const char* aname = get_action_name(); const char* kname = (kind == Expr_result::k_LValue ? "lvalue" : kind == Expr_result::k_RValue ? "rvalue" : "You are in trouble"); os << type.get_human_readable_type() << " [" << kname << "; " << aname; if (function) os << ", call to signature `" << function->get_proto_type().get_encoded_type() << "'"; os << "]"; } /******************************* Functions *******************************/ /** Given two fundamental types, figure out how we can convert between them. We can convert any fundamental type (except void) into any of the others, so no validity checks needed here. */ static Implicit_conversion::Action fundamental_conversion_type(Type src, Type dest) { assert(src.get_kind() == Type::k_Fundamental); assert(dest.get_kind() == Type::k_Fundamental); assert(src.is_valid() && !src.is_void()); assert(dest.is_valid() && !dest.is_void()); src = src.get_unqualified_type(); dest = dest.get_unqualified_type(); if (src == bool_type) { /* bool -> int/double */ if (dest.is_float()) return Implicit_conversion::a_FloatingIntegralConversion; else if (dest.is_same_unqualified_type(int_type)) return Implicit_conversion::a_IntegralPromotion; else return Implicit_conversion::a_IntegralConversion; } else if (src.is_float()) { if (dest == bool_type) { /* fp->bool, 4.12 */ return Implicit_conversion::a_BoolConversion; } else if (dest.is_float()) { /* float->double is a promotion, everything else is a conversion (4.6, 4.8) */ if (src == float_type && dest == double_type) return Implicit_conversion::a_FloatingPromotion; else return Implicit_conversion::a_FloatingConversion; } else { /* must be float->integral */ assert(dest.is_int()); return Implicit_conversion::a_FloatingIntegralConversion; } } else if (src.is_int()) { /* anything smaller than int can be converted to int resp. unsigned int. Hence, formally, short->long is a conversion. */ if (dest == bool_type) return Implicit_conversion::a_BoolConversion; else if (src.get_promoted_integer() == dest) return Implicit_conversion::a_IntegralPromotion; else return Implicit_conversion::a_IntegralConversion; } else { assert(0); } } /** Generate (partial) implicit conversion which converts /ics/ to /arg_type/. Returns true on success. */ static bool gen_builtin_conversions(Implicit_conversion* ics, Type arg_type) { Type ics_type = ics->get_current().type; assert(!arg_type.is_void()); assert(!ics_type.is_void()); assert(arg_type.is_valid()); assert(ics_type.is_valid()); assert(arg_type.get_kind() != Type::k_Function && arg_type.get_kind() != Type::k_Array); /* 4.1 cv-lvalue -> rvalue (nonclass) cv-lvalue -> rvalue (class) */ /* There can be no arg_type which is a function, nor can there be an arg_type which is an array and not an exact match */ // if (ics_type.is_same_unqualified_type(arg_type)) if (!ics->convert_to_rvalue(arg_type)) { return false; } ics_type = ics->get_current().type; if (ics_type == arg_type) return true; switch (ics_type.get_kind()) { case Type::k_Fundamental: /* fundamental types can only be converted into fundamental types or null pointers */ if (arg_type.get_kind() == Type::k_Pointer || arg_type.get_kind() == Type::k_Member) { /* 4.10: npc -> *T */ /* 4.11: npc -> PM */ if (!ics->is_npc()) // FIXME: this is problematic; it might be a null- // pointer constant which we don't recognize. However, // making this just a warning prevents correct // resolution when someone has a ctor which takes // both int or T* args. // ics->warn_if_used("possibly invalid conversion of integer to pointer used"); return false; if (arg_type.get_kind() == Type::k_Pointer) ics->add_conversion(Implicit_conversion::a_PointerConversion, arg_type); else ics->add_conversion(Implicit_conversion::a_PtrMemConversion, arg_type); return true; } else if (arg_type.get_kind() == Type::k_Fundamental) { /* 4.5: integral promotions (FOO int -> int, bool -> int) */ /* 4.6: fp promotions (float -> double) */ /* 4.7: integral conversions (int/bool -> any int) */ /* 4.8: fp conversions (fp -> fp) */ /* 4.9: fpint conversions (fp -> int, int/enum -> fp */ /* 4.12: bool conv (int/fp/enum -> bool) */ /* essentially, we can convert anything to anything else, we just have to figure out how */ ics->add_conversion(fundamental_conversion_type(ics_type, arg_type), arg_type); return true; } else { return false; } case Type::k_Pointer: if (arg_type.get_kind() == Type::k_Pointer) { /* pointer-to-pointer conversions */ Type sp = ics_type.get_basis_type(); Type tp = arg_type.get_basis_type(); if (tp.is_void() && !sp.is_void()) { /* 4.10: cv-T* can be converted to cv-void* */ ics_type = void_type.with_qualifiers(sp).make_pointer_type(); ics->add_conversion(Implicit_conversion::a_PointerConversion, ics_type); } else if (tp.get_kind() == Type::k_Userdef && sp.get_kind() == Type::k_Userdef && !sp.is_same_unqualified_type(tp)) { /* 4.10: cv-Derived can be converted to cv-Base */ // FIXME: I think when it is ambiguous it still takes // part in overload resolution; 4.10 isn't entirely clear // about that Class_symbol* sclass = dynamic_cast(sp.get_type_symbol()); Class_symbol* tclass = dynamic_cast(tp.get_type_symbol()); if (!sclass || !tclass || !tclass->is_unique_base_class_of(sclass)) return false; ics_type = tclass->get_type().with_qualifiers(sp).make_pointer_type(); ics->add_conversion(Implicit_conversion::a_PointerConversion, ics_type); } /* 4.3: we can add qualifiers */ if (ics_type != arg_type) { if (!ics_type.is_qualification_convertible_to(arg_type)) return false; ics->add_conversion(Implicit_conversion::a_QualificationAdjustment, arg_type); } return true; } else if (arg_type.get_unqualified_type() == bool_type) { /* 4.12: bool conv (ptr -> bool) */ ics->add_conversion(Implicit_conversion::a_BoolConversion, arg_type); return true; } else { return false; } case Type::k_Reference: assert(0); return false; case Type::k_Function: /* 4.3: function -> pointer. When we end up here, we attempt an incompatible conversion. */ return false; case Type::k_Array: /* 4.2: array -> pointer. When we end up here, we attempt an incompatible conversion. */ return false; case Type::k_Member: /* 4.3: cv-PM -> more-cv-PM add cv qualifiers */ /* 4.11: cv-PM-base -> cv-PM-derived */ /* 4.12: bool conv (PM -> bool) */ if (arg_type.get_kind() == Type::k_Member) { Type sct = ics_type.get_class_type(); Type tct = arg_type.get_class_type(); if (!sct.is_same_unqualified_type(tct)) { /* 4.11: cv-PM-of-Base -> cv-PM-of-Derived */ Class_symbol* sclass = dynamic_cast(sct.get_type_symbol()); Class_symbol* tclass = dynamic_cast(tct.get_type_symbol()); // FIXME: the same ambiguity problem as above strikes here, too if (!sclass || !tclass || !sclass->is_unique_base_class_of(tclass)) return false; // FIXME: classes don't have cv-qualifiers in member pointers, // so there's no need to do with_qualifiers here. Check that. ics_type = tclass->get_type().make_member_type(ics_type.get_member_type()); ics->add_conversion(Implicit_conversion::a_PtrMemConversion, ics_type); } if (ics_type != arg_type) { /* qualification conversion */ if (!ics_type.is_qualification_convertible_to(arg_type)) return false; ics->add_conversion(Implicit_conversion::a_QualificationAdjustment, arg_type); } return true; } else if (arg_type.get_unqualified_type() == bool_type) { ics->add_conversion(Implicit_conversion::a_BoolConversion, arg_type); return true; } else { return false; } case Type::k_Userdef: { Type_symbol* sym = ics_type.get_type_symbol(); if (sym->get_kind() != Symbol::k_Enum) return false; if (arg_type.get_unqualified_type() == bool_type) { /* 4.12: enum -> bool */ ics->add_conversion(Implicit_conversion::a_BoolConversion, arg_type); return true; } else if (arg_type.is_int()) { /* 4.7: enum -> int */ ics->add_conversion(Implicit_conversion::a_IntegralConversion, arg_type); return true; } else { return false; } } case Type::k_Template: assert(0); case Type::k_Ellipsis: case Type::k_Nothing: return false; } } /** Generate all conversions that are possible with constructors. */ static void gen_constructors(const Expr_result& expr, Type arg_type, Function_signature* symbol_hint, std::vector* icv) { if (arg_type.get_kind() != Type::k_Userdef) return; Class_symbol* sym = dynamic_cast(arg_type.get_type_symbol()); if (!sym || !sym->is_defined()) return; /* it is a class. Iterate through all its one-arg constructors */ Function_symbol* fsym = dynamic_cast(sym->get_scope()->lookup_here(Symbol_name::CONSTRUCTOR_NAME, true).untag); if (!fsym) /* no constructors defined */ return; for (Function_symbol::Sig_it i = fsym->sig_begin(); i != fsym->sig_end(); ++i) { Function_signature* sig = *i; if (!sig->is_declared() || sig->get_proto_type().get_num_function_args() != 1) continue; if (sig->get_function_specifiers() & f_Explicit) continue; /* okay, it's a possible constructor. Figure out how to call it. */ Implicit_conversion* ic = generate_implicit_conversion(expr, sig->get_proto_type().get_function_arg(0), symbol_hint, false /* no user-defined */, true /* is copy-initialisation */, false /* not implicit object arg */); if (ic) { ic->add_step(Implicit_conversion::Step(arg_type.get_unqualified_type(), Expr_result::k_RValue, sig, Implicit_conversion::a_CtorCall)); /* do const adjustments etc. */ if (ic->convert_to_rvalue(arg_type)) icv->push_back(ic); } } } class Class_op_lookup_helper : public Class_lookup_helper { Type t; }; PUBLIC Class_op_lookup_helper::Class_op_lookup_helper(Type t) : t(t) { } PUBLIC bool Class_op_lookup_helper::predicate(Class_symbol* sym) { Function_symbol* fsym = dynamic_cast(sym->lookup_helper(Symbol_name::CONVERSION_OPERATOR_NAME).untag); if (!fsym) return false; Function_signature* fsig = fsym->get_function_signature(t, 0); return fsig != 0; } /** Check whether /what/'s operator is visible when looking from /sym/. */ PUBLIC bool Class_op_lookup_helper::is_visible_in(Class_symbol* what, Class_symbol* sym) { add_class(sym); finish(sym); for (classes_t::const_iterator i = result_set.begin(); i != result_set.end(); ++i) { if (what == *i) return true; } return false; } /******************************* Functions *******************************/ void enumerate_conversion_ops(const Expr_result& expr, Conversion_op_map* output) { if (expr.get_type().get_kind() != Type::k_Userdef) return; Class_symbol* sym = dynamic_cast(expr.get_type().get_type_symbol()); if (!sym) return; if (!sym->is_defined()) compile_error("attempting to use undefined type `" + sym->get_name() + "'"); /* It's a class. Enumerate all operators defined in the derivation tree. Then look which of them are visible. */ Class_symbol::bases_t list; list.push_back(sym); sym->enumerate_base_classes(true, &list); for (Class_symbol::bases_t::iterator i = list.begin(); i != list.end(); ++i) { Function_symbol* fsym = dynamic_cast((*i)->lookup_helper(Symbol_name::CONVERSION_OPERATOR_NAME).untag); if (!fsym) continue; for (Function_symbol::Sig_it j = fsym->sig_begin(); j != fsym->sig_end(); ++j) { /* class members are always known */ assert((*j)->is_declared()); /* /j/ now is an operator function signature from class /i/. We have to check whether this signature is visible from /sym/. */ Class_op_lookup_helper lh(expr.get_type().make_member_type((*j)->get_proto_type())); if (lh.is_visible_in(*i, sym)) (*output)[*j]++; } } } /** Generate all conversions using a conversion function. Returns true if there was at least one such conversion. */ static bool gen_conv_ops(const Expr_result& expr, Type arg_type, Function_signature* symbol_hint, std::vector* icv) { Conversion_op_map sigs; enumerate_conversion_ops(expr, &sigs); /* Now, /sigs/ contains all operators, with visibility count. Generate the appropriate number of conversion sequences. */ bool rv = false; for (std::map::iterator i = sigs.begin(); i != sigs.end(); ++i) { Implicit_conversion* ics = new Implicit_conversion(expr, symbol_hint); /* convert the source to the implicit object argument */ if (!ics->convert_reference(i->first->get_this_type())) continue; /* call the function */ Type type = i->first->get_return_type(); Expr_result interm_expr; interm_expr.set_value(0, type); ics->add_step(Implicit_conversion::Step(interm_expr.get_type(), interm_expr.get_kind(), i->first, Implicit_conversion::a_ConversionOp)); if (i->second != 1) ics->set_ambiguous(); /* convert result to target */ // FIXME: we should use actual overload resolution here. This // makes a difference when template constructors / converters // enter the game. Probably it's even better to do that // directly in generate_implicit_conversion. Implicit_conversion* final = generate_implicit_conversion(interm_expr, arg_type, symbol_hint, false /* no user-defined */, true /* is copy-initialisation; this is completely egal since we don't use user convs. */, false /* not implicit object arg */); if (final) { ics->append_from(final); icv->push_back(ics); rv = true; } } return rv; } /** Generate all implicit conversion candidates for an expression. \param expr the "input" expression \param arg_type the target type to convert to \param symbol_hint value to put into the ICS as symbol hint. This is used for expressions like "f(g)" where "g" is an overloaded function. Normally, the "g" node of "expr.tree" should be annotated with "symbol_hint", but we don't know that until we do overload resolution. \param with_userdef include user-defined conversions \param candidates output space */ void gen_candidates(Expr_result expr, Type arg_type, Function_signature* symbol_hint, bool with_userdef, bool is_object, std::vector* candidates) { if (expr.is_bound_member()) { /* I'm not 100% sure what to do here. Probably it's simplest to simply generate no candidates; callers will notice and say so. The alternative would be to compile_error(). */ return; } if (expr.is_function()) { /* expr is a function name. Generate all conversions which convert any of these functions into a target. */ for (Function_symbol::Sig_it i = expr.get_function()->sig_begin(); i != expr.get_function()->sig_end(); ++i) { Expr_result nexpr; nexpr.set_value(expr.get_tree(), (*i)->get_pointer_type()); gen_candidates(nexpr, arg_type, *i, with_userdef, is_object, candidates); } return; } /* Normal ICS generation follows: */ assert(expr.get_type().get_kind() != Type::k_Reference); if (arg_type.get_kind() == Type::k_Reference) { Type ref_type = arg_type.get_basis_type(); /* references, 8.5.3. p5: if the initializer is a reference-compatible lvalue, or can be converted to a reference-compatible "T3&" The implicit object arg can also be bound to an rvalue. */ if (is_object || expr.is_lvalue()) { /* try to bind directly */ Implicit_conversion* idirect = new Implicit_conversion(expr, symbol_hint); if (idirect->convert_reference(ref_type)) { candidates->push_back(idirect); /* No matter what happens, this conversion can't be beaten, so no need to try the others */ return; } } if (with_userdef && expr.get_type().get_kind() == Type::k_Userdef) { /* try to bind with conversion operator. If there was such a conversion, don't try the others. The others would involve a temporary. */ if (gen_conv_ops(expr, arg_type, symbol_hint, candidates)) return; } /* otherwise, reference shall not be volatile but const */ if (ref_type.is_qualified(Type::q_Const) && !ref_type.is_qualified(Type::q_Volatile)) { // FIXME: I'm not 100% sure about this one if (Implicit_conversion* ics = generate_implicit_conversion(expr, ref_type, symbol_hint, with_userdef /* with user-defined */, true /* is copy-init */, false /* not implicit object arg. We don't get here when it is the i.o.a. */)) { ics->add_step(ICS_Step(ref_type, Expr_result::k_LValue, Implicit_conversion::a_BindReferenceToTemporary)); // ics->bind_to_temporary(ref_type); candidates->push_back(ics); } } } else { /* target is by-value thing */ assert(expr.get_type().is_valid()); arg_type = arg_type.get_unqualified_type(); Implicit_conversion* im = new Implicit_conversion(expr, symbol_hint); if (gen_builtin_conversions(im, arg_type)) candidates->push_back(im); if (with_userdef) { if (arg_type.get_kind() == Type::k_Userdef) gen_constructors(expr, arg_type, symbol_hint, candidates); if (expr.get_type().get_kind() == Type::k_Userdef) gen_conv_ops(expr, arg_type, symbol_hint, candidates); } } } /** Generate all ICS's and return the best one. Returns an ambiguous sequence if conversion is ambiguous, null if impossible. */ Implicit_conversion* generate_implicit_conversion(Expr_result expr, Type arg_type, Function_signature* symbol_hint, bool with_userdef, bool is_copy_initialisation, bool is_implicit_object_arg) { /* shortcut: there are no conversions from void */ if (expr.get_type().is_void()) return 0; std::vector candidates; gen_candidates(expr, arg_type, symbol_hint, with_userdef, is_implicit_object_arg, &candidates); if (candidates.empty()) return 0; ICS_Types::Compare compare = ICS_Types::c_CompareWithInitRules; if (is_copy_initialisation && arg_type.is_class_type() && !expr.get_type().is_same_unqualified_type(arg_type)) { /* special case, 13.3.1.4: in an expression of the form Arg_type x = expr where Arg_type is a class type and expr has not the same type as Arg_type, we have to do overload resolution with Argument list = expr Function list = all constructors of Arg_type all conversion functions of expr without user-defined conversions. We'd end up with a number of SCSs, pick the best, tack our function at the end, and add more SCSs to convert the function result into the target type. When we're here, we already have the complete ICS including the two SCSs and the user-defined converter, so all we have to do is to compare the ICSs *before* the user-defined function. */ compare = ICS_Types::c_CompareBeforeUserConversion; } /* figure out best one. step 1) find one which is not worse than all others step 2) ensure that this one is actually better */ Implicit_conversion* best = candidates.front(); for (std::vector::size_type i = 1; i < candidates.size(); ++i) if (candidates[i]->is_better_than(best, compare)) best = candidates[i]; for (std::vector::size_type i = 0; i < candidates.size(); ++i) { if (best != candidates[i] && !best->is_better_than(candidates[i], compare)) { /* best is not uniquely better than this one. Ambiguous. */ best->set_ambiguous(); return best; } } return best; }