/** * \file function.cpp * \brief Function definitions * \author Stefan Reuther * * This module defines classes to manage functions and function * signatures. */ INTERFACE: #include #include "symbol_table.h" #include "type_rep.h" #include "symbol_name.h" class Class_symbol; class Block_scope; class Function_symbol; class Variable_symbol; class Function_signature : public Symbol { /* the declared type, i.e. the type of the prototype */ Type proto_type; /* the type of the implicit object parameter */ Type this_type; /* the type used when calling this function. */ Type call_type; Storage_class_specifier storage_spec; Function_specifier_set function_spec; bool builtin; bool generated; Function_symbol* backlink; Ptree* definition; Ptree* initializers; public: typedef std::vector Par_vec; private: Par_vec parameters; }; class Function_symbol : public Symbol { typedef std::vector Sig_vec; Sig_vec signatures; Abstract_scope* declared_scope; Symbol_name::Kind fun_kind; public: enum Add_arg { must_be_declared, must_be_new, may_be_anything }; typedef Sig_vec::const_iterator Sig_it; Sig_it sig_begin() const { return signatures.begin(); } Sig_it sig_end() const { return signatures.end(); } Symbol_name::Kind get_function_kind() const { return fun_kind; } }; IMPLEMENTATION: #include "except.h" #include "class.h" #include "downcast.h" #include "annotation.h" /**************************** Function_symbol ****************************/ PUBLIC Function_symbol::Function_symbol(Abstract_scope* declared_scope, Symbol_name::Kind fun_kind) : declared_scope(declared_scope), fun_kind(fun_kind) { /* avoid the wording "undefined function" in dumps. A function signature is not an object. */ set_status(st_Defined); } PUBLIC inline Abstract_scope* Function_symbol::get_declared_scope() const { return declared_scope; } PUBLIC Function_symbol::Kind Function_symbol::get_kind() const { return k_Function; } PUBLIC void Function_symbol::fill_in_mangled_names(bool ignore_if_one) { if (ignore_if_one && signatures.size() == 1) { if (signatures.front()->get_name().length() == 0) signatures.front()->set_name(get_name(), get_basename().length()); return; } for (Sig_it i = signatures.begin(); i != signatures.end(); ++i) { if ((*i)->get_name().length() == 0) { std::string s = Symbol_name::get_mangled_function_name(get_basename(), (*i)->get_proto_type(), (*i)->get_this_type()); (*i)->set_name(declared_scope->get_unique_name(s), s.length()); } } } /** Add a signature. \param t type of the function \param this_type type for this pointer, if needed \param sc storage class. May only be s_None when this is a definition of a function *or* a declaration at top-level. \param f function specifier set \param what_to_do what actions are we allowed to do? \return the created signature \throw on error */ PUBLIC Function_signature* Function_symbol::add_signature(Type t, Type this_type, Storage_class_specifier sc, Function_specifier_set f, Add_arg what_to_do) { assert(sc == s_Extern || sc == s_Static || sc == s_Member || sc == s_None); /* qualifiers of t actually apply to this_type, i.e. `void(int) const' in `Foo' actually is `void(int)' in `const Foo' */ if (this_type.is_valid()) { if (t.is_qualified(Type::q_Restrict)) compile_error("restrict not allowed as function type qualifier"); this_type.copy_qualifiers(t); t = t.get_unqualified_type(); } else { if (t.is_qualified()) compile_error("non-member function can't be qualified"); } /* look up function signature */ std::string tsig = t.get_function_signature(); Function_signature* found_sig = 0; for (Sig_vec::iterator i = signatures.begin(); i != signatures.end(); ++i) { Function_signature* sig = *i; if (sig->get_proto_type().get_function_signature() == tsig) if (!found_sig || sig->get_this_type() == this_type) found_sig = sig; } if (found_sig) { /* we already have a function which takes the same parameters */ if (found_sig->get_storage_specifier() == s_Member) { /* the existing function is a member. This one must be a member, too; maybe with different this_type. */ if (sc != s_None && sc != s_Member) compile_error("new static function collides with existing member"); assert(this_type.is_valid()); if (this_type == found_sig->get_this_type()) { if (what_to_do == must_be_new) compile_error("function already declared"); found_sig->merge_fspec(f); return found_sig; } /* fallthrough to creation of new signature */ } else { /* the existing function is not a member. this_type is irrelevant */ if (this_type.is_valid() && this_type.is_qualified()) compile_error("static functions may not be qualified"); if (sc == s_Member) compile_error("new member function collides with existing static function"); if (what_to_do == must_be_new) compile_error("function already declared"); found_sig->merge_fspec(f); return found_sig; } } if (what_to_do == must_be_declared) compile_error("can't introduce new signatures here"); /* okay, it's a new function */ Type call_type; if (sc == s_None) sc = s_Extern; if (sc != s_Member) { // FIXME: check function kind? this_type = Type(); call_type = t; } else { if (get_function_kind() == Symbol_name::k_Constructor) { // FIXME: HACK HACK HACK. Replace the return type. std::string s = t.get_encoded_type(); s.erase(s.length()-1); call_type = Type(s); } else if (get_function_kind() == Symbol_name::k_Destructor) { call_type = make_unary_function_type(this_type.make_reference_type(), void_type); } else if (get_function_kind() == Symbol_name::k_Conversion) { call_type = make_unary_function_type(this_type.make_reference_type(), t.get_return_type()); } else { call_type = t.with_first_arg(this_type.make_reference_type()); } } Function_signature* sig = new Function_signature(t, this_type, call_type, sc, f, this); signatures.push_back(sig); return sig; } /** true iff function is overloaded. */ PUBLIC bool Function_symbol::is_overloaded() const { /* only count declared functions: void foo() { extern void foo(int); } void bar() { foo; // foo is not an overloaded function here } // although we know the second signature */ Sig_vec::size_type n = 0; for (Sig_vec::const_iterator i = signatures.begin(); i != signatures.end(); ++i) if ((*i)->is_declared()) ++n; return n != 1; } /** Get type of this function. Only works for non-overloaded functions. */ PUBLIC inline Type Function_symbol::get_type() const { return get_nonoverloaded_signature()->get_proto_type(); } /** Get signature of this function. Only works for non-overloaded functions. */ PUBLIC Function_signature* Function_symbol::get_nonoverloaded_signature() const { assert(!is_overloaded()); for (Sig_vec::const_iterator i = signatures.begin(); i != signatures.end(); ++i) if ((*i)->is_declared()) return *i; assert(0); } /** Get function having a particular pointer type. \param type desired type (must be pointer-to-member or pointer) \param ambig if non-null, stores "true" if it fails due to ambiguity, "false" if it fails due to non-existance of signature. \return the signature, or null */ PUBLIC Function_signature* Function_symbol::get_function_signature(Type type, bool* ambig) const { assert(type.get_kind() == Type::k_Pointer || type.get_kind() == Type::k_Member); Function_signature* p = 0; for (Sig_vec::const_iterator i = signatures.begin(); i != signatures.end(); ++i) { if ((*i)->is_declared() && (*i)->has_pointer_type(type)) { if (p) { if (ambig) *ambig = true; return 0; // ambiguous } else { p = *i; } } } if (ambig) *ambig = false; return p; } PUBLIC void Function_symbol::dump(std::ostream& os) { Symbol::dump(os); for (Sig_vec::iterator i = signatures.begin(); i != signatures.end(); ++i) { os << "\n " << (*i)->get_name() << ":\n "; (*i)->dump(os); } } /*************************** Function_signature **************************/ /** Construct function signature. \param t type, for example "void (*)(int)". \param this_type type of this pointer, with possible qualifications, e.g. "const X" for a const member function of X; invalid if function is static or non-member. \param sc storage class (member, extern, static) \param f function specifiers (inline, virtual, ...) */ PUBLIC Function_signature::Function_signature(Type t, Type this_type, Type call_type, Storage_class_specifier sc, Function_specifier_set f, Function_symbol* backlink) : proto_type(t), this_type(this_type), call_type(call_type), storage_spec(sc), function_spec(f), builtin(false), generated(false), backlink(backlink), definition(0) { assert(this_type.is_valid() == (sc == s_Member)); } /** Make a builtin function signature. These are used for overload resolution, to resolve builtin operators. This is just a handy shortcut. */ PUBLIC static Function_signature* Function_signature::make_builtin(Type t) { Function_signature* fsig = new Function_signature(t, Type(), t, s_Extern, f_None, 0); fsig->set_name("builtin", 7); fsig->set_builtin(); return fsig; } /** Get return type. */ PUBLIC Type Function_signature::get_return_type() const { return get_proto_type().get_return_type(); } /** Get proto-type (args + return type). */ PUBLIC inline Type Function_signature::get_proto_type() const { return proto_type; } /** Get type used for calling this function. */ PUBLIC inline Type Function_signature::get_call_type() const { return call_type; } /** Get type of *this. (The actual type of /this/ is q = get_this_type().make_pointer_type().with_qualifier(q_Const);) */ PUBLIC inline Type Function_signature::get_this_type() const { return this_type; } /** True iff this function signature can be stored in a pointer of type t. E.g., for a function "void p(int)", this returns true if and only if t is "void (*)(int)". For member functions, we need some more elaborate conditions to handle base class relationships, i.e. a "void (Base::*)(int)" can be stored in "void (Derived::*)(int)". */ PUBLIC bool Function_signature::has_pointer_type(Type t) const { if (this_type.is_valid()) { /* this is a member function */ assert(storage_spec == s_Member); /* target must be pointer to member */ if (t.get_kind() != Type::k_Member || t.get_member_type().get_kind() != Type::k_Function) return false; /* signature must fit */ if (t.get_member_type() != proto_type) return false; /* qualifications on class type must fit: "void (c::*pmf)() = &c::const_mf" works, "void (c::*pmf)() const = &c::nonconst_mf" doesn't */ Type cl = t.get_class_type(); if (cl.is_more_qualified_than(this_type)) return false; /* derivation: "void (derived::*pmf)() = &base::mf" */ return cl.get_unqualified_type() == this_type.get_unqualified_type() || downcast(this_type.get_type_symbol())->is_unique_base_class_of(downcast(cl.get_type_symbol())); } else { /* this is a static function */ if (t.get_kind() != Type::k_Pointer) return false; return t.get_basis_type().is_same_unqualified_type(proto_type); } } /** Get type of expression "&this_function". */ PUBLIC Type Function_signature::get_pointer_type() const { if (this_type.is_valid()) { return this_type.make_member_type(proto_type); } else { return proto_type; } } /** Get storage specifier. One of s_Static/s_Member/s_Extern. */ PUBLIC inline Storage_class_specifier Function_signature::get_storage_specifier() const { return storage_spec; } /** Get list of function specifiers. */ PUBLIC inline Function_specifier_set Function_signature::get_function_specifiers() const { return function_spec; } /** Merge function specifiers. */ PUBLIC void Function_signature::merge_fspec(Function_specifier_set fspec) { if (fspec & ~f_Inline) compile_error("only the `inline' specifier can be added to a declared function"); function_spec |= fspec; } /** "Builtin" flag. True iff this is a builtin operator. Only used during overload resolution. */ PUBLIC inline bool Function_signature::is_builtin() const { return builtin; } PUBLIC inline void Function_signature::set_builtin() { builtin = true; } /** "Generated" flag. True iff this is a generated function. */ PUBLIC inline bool Function_signature::is_generated() const { return generated; } PUBLIC inline void Function_signature::set_generated() { generated = true; if (!is_declared()) set_status(st_Declared); } /** Get function symbol of which this is an instance. */ PUBLIC inline Function_symbol* Function_signature::get_function() const { return backlink; } /** Get body of this function. \pre is_defined(). */ PUBLIC inline Ptree* Function_signature::get_body() const { assert(is_defined()); return definition; } /** Get initializers. Only valid for constructors. The initializer Ptree has no direct mapping into C++. It is a list of elements of the form NonLeaf [Symbol, Type] Name = Initializer-expression-or-null-if-uninitialized */ PUBLIC inline Ptree* Function_signature::get_initializers() const { assert(is_defined()); return initializers; } /** Set body and initializers. See get_initializers() and get_body() for details. */ PUBLIC void Function_signature::set_body(Ptree* tree, Ptree* init) { set_status(st_Defined); definition = tree; initializers = init; } PUBLIC Function_signature::Par_vec::const_iterator Function_signature::par_begin() const { return parameters.begin(); } PUBLIC Function_signature::Par_vec::const_iterator Function_signature::par_end() const { return parameters.end(); } PUBLIC void Function_signature::add_parameter(Variable_symbol* vsym) { assert(vsym->get_type().is_same_unqualified_type(get_proto_type().get_function_arg(parameters.size()))); parameters.push_back(vsym); } PUBLIC Symbol::Kind Function_signature::get_kind() const { return k_Function; } PUBLIC void Function_signature::dump(std::ostream& os) { Symbol::dump(os); os << ", type is `" << proto_type.get_human_readable_type() << "'\n storage: " << get_storage_specifier_name(storage_spec) << ", function specifiers: " << get_function_specifier_name(function_spec) << ", class type: "; if (this_type.is_valid()) os << "`" << this_type.get_human_readable_type() << "'"; else os << "(none)"; if (is_generated()) os << ", synthesized"; if (Symbol_table::has_dump_flag('b')) { if (initializers) { os << "\n Member Initializers:\n"; print_annotated_tree(os, " | ", initializers, Symbol_table::has_dump_flag('c')); } if (definition) { os << "\n Body:\n"; print_annotated_tree(os, " | ", definition, Symbol_table::has_dump_flag('c')); } } }