/** * \file expr_result.cpp */ INTERFACE: #include #include "annotation.h" #include "type_rep.h" class Function_symbol; struct Expr_result { struct Dummy; enum Kind { k_RValue, k_LValue, k_Function, k_BoundMember, k_BoundPMF }; private: Ptree* tree; // result tree Type type; // result type Function_symbol* symbol; // function symbol, if result is an ambiguous function name Kind kind; Ptree* obj_tree; // associated object for a member function call public: Ptree* get_tree() const { return tree; } const Type& get_type() const { return type; } Function_symbol* get_function() const { return symbol; } Kind get_kind() const { return kind; } Ptree* get_object() const { return obj_tree; } bool is_function() const { return kind == k_Function; } bool is_bound_member() const { return kind == k_BoundMember || kind == k_BoundPMF; } bool is_bound_pmf() const { return kind == k_BoundPMF; } void set_kind(Kind k) { kind = k; } void set_tree(Ptree* t) { tree = t; } /* /symbol/ deserves an explanation: at certain places, an overloaded function name can appear. According to 13.4: - initializer for a variable - RHS of an assignment - parameter of a function - parameter of a user-defined operator - return value - in a type cast (i.e. `(int (*)(int)) foo') - inside a pair of parens which is one of the above When we encounter such a case, type.is_valid() will be false (and Kind will be k_Function) and symbol will point to the function being used/called. At all other places, we reject overloaded functions. When a symbol like this is found in one of the above cases, the caller must figure out what it is, and annotate it. */ /* Invariant: type is never a reference */ /* Invariant: type.is_valid() == (kind == k_LValue || kind == k_RValue) */ // these two are needed by Paranoid_visitor & friends Expr_result() : tree(0), type(), symbol(), obj_tree(0) { } Expr_result(Dummy*) : tree(0), type(), symbol(), obj_tree(0) { } // normal expression value template Expr_result(Annotated* tree, Kind k) : tree(tree), type(tree->get_type()), symbol(0), kind(k), obj_tree(0) { assert(type.is_valid()); } Expr_result(Ptree* tree, Type t, Kind k) : tree(tree), type(t), symbol(0), kind(k), obj_tree(0) { assert(type.is_valid()); } // function symbol template Expr_result(Annotated* tree, Function_symbol* sym) : tree(tree), type(), symbol(sym), kind(k_Function), obj_tree(0) { } // bound member function Expr_result(Ptree* object, Ptree* function, Function_symbol* sym) : tree(function), type(), symbol(sym), kind(k_BoundMember), obj_tree(object) { } Expr_result(Ptree* object, Ptree* function, Type t) : tree(function), type(t), symbol(0), kind(k_BoundPMF), obj_tree(object) { } }; IMPLEMENTATION: #include #include "except.h" #include "implicit_conversion.h" #include "overload_resolver.h" /** True iff this is a lvalue, 3.10p1 */ PUBLIC inline bool Expr_result::is_lvalue() const { return kind == k_LValue; } PUBLIC inline bool Expr_result::is_value() const { return kind == k_LValue || kind == k_RValue; } PUBLIC inline void Expr_result::convert_to(Type t) { assert(t.is_valid() && !t.is_class_type()); if (t != type) { set_value(make_cast_expr(tree, t), t); } } PUBLIC inline void Expr_result::convert_to_qual(Type t) { assert(t.is_valid() && t.is_same_unqualified_type(type)); if (t != type) set_value(make_cast_expr_unchecked(tree, t), t); } PUBLIC void Expr_result::set_value(Ptree* value, Type t) { assert(t.is_valid()); tree = value; obj_tree = 0; symbol = 0; if (t.get_kind() == Type::k_Reference) { type = t.get_basis_type(); kind = k_LValue; } else { type = t; kind = k_RValue; } } /** lvalue to rvalue conversion, 4.1 */ PUBLIC void Expr_result::convert_to_rvalue() { if (!type.is_valid()) { compile_error("attempt to access value of an expression without type"); } else if (!is_lvalue()) { /* intentionally left blank */ } else if (type.get_kind() != Type::k_Array && type.get_kind() != Type::k_Function) { if (!type.is_complete()) compile_error("attempt to access object of incomplete type"); if (!type.is_class_type()) convert_to(type.get_unqualified_type()); kind = k_RValue; } } /** Array to pointer conversion, 4.2 */ PUBLIC void Expr_result::convert_to_pointer() { if (!type.is_valid()) { compile_error("attempt to access value of an expression without type"); } else if (type.get_kind() == Type::k_Array) { /* FIXME: the string-literal-to-unqualified-pointer conversion is NOT handled (yet) because it's deprecated. */ convert_to(type.get_basis_type().make_pointer_type()); kind = k_RValue; } } /** Function-to-pointer conversion, 4.3 */ PUBLIC void Expr_result::convert_to_fpointer() { if (!type.is_valid()) { compile_error("attempt to access value of an expression without type"); } else if (type.get_kind() == Type::k_Function) { convert_to(type.make_pointer_type()); kind = k_RValue; } } /** Integral promotions, 4.5 */ PUBLIC inline void Expr_result::do_integral_promotions() { convert_to_rvalue(); convert_to(type.get_promoted_integer()); } /* Missing: 4.6 to 4.9 */ /** Convert to boolean, 4.10 */ PUBLIC void Expr_result::convert_to_bool() { do_std_conversions(); if (type.is_arithmetic_type() || type.is_enum_type() || type.get_kind() == Type::k_Pointer || type.get_kind() == Type::k_Member) { convert_to(bool_type); } else { compile_error("unable to convert `" + type.get_human_readable_type() + "' to bool"); } } /** Adjust reference types, 5p6 */ PUBLIC void Expr_result::adjust_reference() { if (type.get_kind() == Type::k_Reference) { convert_to(type.get_basis_type()); kind = k_LValue; } } /** Standard conversions, 5p8. This corresponds to loading the value into a register or somesuch. */ PUBLIC void Expr_result::do_std_conversions() { convert_to_rvalue(); convert_to_pointer(); convert_to_fpointer(); } PUBLIC bool Expr_result::is_modifyable_lvalue() const { return kind == k_LValue && !type.is_qualified(Type::q_Const); } /** True iff this is (may be) a null pointer constant. */ PUBLIC bool Expr_result::is_npc() const { using namespace std; if (!type.is_int() || !tree) return false; /* only literal nulls allowed */ if (Leaf* l = dynamic_cast(tree)) { char* c = l->ToString(); if (*c == '0' && c[strspn(c, "0xXuUlL")] == 0) return true; } return false; }