| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- // Filename: cppStructType.cxx
- // Created by: drose (19Oct99)
- //
- ////////////////////////////////////////////////////////////////////
- //
- // PANDA 3D SOFTWARE
- // Copyright (c) Carnegie Mellon University. All rights reserved.
- //
- // All use of this software is subject to the terms of the revised BSD
- // license. You should have received a copy of this license along
- // with this source code in a file named "LICENSE."
- //
- ////////////////////////////////////////////////////////////////////
- #include "cppStructType.h"
- #include "cppTypedefType.h"
- #include "cppScope.h"
- #include "cppTypeProxy.h"
- #include "cppTemplateScope.h"
- #include "cppFunctionGroup.h"
- #include "cppFunctionType.h"
- #include "cppTBDType.h"
- #include "indent.h"
- #include "cppParser.h"
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::Base::output
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CPPStructType::Base::
- output(ostream &out) const {
- if (_is_virtual) {
- out << "virtual ";
- }
- out << _vis << " " << *_base;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::Constructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPStructType::
- CPPStructType(CPPStructType::Type type, CPPIdentifier *ident,
- CPPScope *current_scope, CPPScope *scope,
- const CPPFile &file) :
- CPPExtensionType(type, ident, current_scope, file),
- _scope(scope)
- {
- _subst_decl_recursive_protect = false;
- _incomplete = true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::Copy Constructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPStructType::
- CPPStructType(const CPPStructType ©) :
- CPPExtensionType(copy),
- _scope(copy._scope),
- _incomplete(copy._incomplete),
- _derivation(copy._derivation)
- {
- _subst_decl_recursive_protect = false;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::Copy Assignment Operator
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CPPStructType::
- operator = (const CPPStructType ©) {
- CPPExtensionType::operator = (copy);
- _scope = copy._scope;
- _incomplete = copy._incomplete;
- _derivation = copy._derivation;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::append_derivation
- // Access: Public
- // Description: A handy function used while parsing to add a new base
- // class to the list of classes (or structs) this class
- // derives from.
- ////////////////////////////////////////////////////////////////////
- void CPPStructType::
- append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) {
- if (base != NULL) {
- // Unwrap any typedefs, since we can't inherit from a typedef.
- CPPTypedefType *def = base->as_typedef_type();
- while (def != NULL) {
- base = def->_type;
- def = base->as_typedef_type();
- }
- Base b;
- b._base = base;
- b._vis = vis;
- b._is_virtual = is_virtual;
- _derivation.push_back(b);
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::get_scope
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPScope *CPPStructType::
- get_scope() const {
- return _scope;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::is_abstract
- // Access: Public
- // Description: Returns true if this struct declaration is abstract,
- // e.g. it contains or inherits at least one method that
- // is pure virtual.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- is_abstract() const {
- VFunctions funcs;
- get_pure_virtual_funcs(funcs);
- return !funcs.empty();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::is_trivial
- // Access: Public, Virtual
- // Description: Returns true if the type is considered a Plain Old
- // Data (POD) type.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- is_trivial() const {
- // Make sure all base classes are trivial.
- Derivation::const_iterator di;
- for (di = _derivation.begin(); di != _derivation.end(); ++di) {
- CPPStructType *base = (*di)._base->as_struct_type();
- if (base != NULL && !base->is_trivial()) {
- return false;
- }
- }
- assert(_scope != NULL);
- // Make sure all members are trivial.
- CPPScope::Variables::const_iterator vi;
- for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
- CPPInstance *instance = (*vi).second;
- assert(instance != NULL);
- if (instance->_storage_class & CPPInstance::SC_static) {
- // Static members don't count.
- continue;
- }
- if (instance->_initializer != NULL) {
- // A member with an initializer means the default constructor would
- // assign a value. This means the type can't be trivial.
- return false;
- }
- // Finally, check if the data member itself is non-trivial.
- assert(instance->_type != NULL);
- if (!instance->_type->is_trivial()) {
- return false;
- }
- }
- // Now look for functions that are virtual or con/destructors.
- bool is_default_constructible = true;
- CPPScope::Functions::const_iterator fi;
- for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
- CPPFunctionGroup *fgroup = (*fi).second;
- CPPFunctionGroup::Instances::const_iterator ii;
- for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) {
- CPPInstance *inst = (*ii);
- if (inst->_storage_class & CPPInstance::SC_virtual) {
- // Virtual functions are banned right off the bat.
- return false;
- }
- assert(inst->_type != (CPPType *)NULL);
- CPPFunctionType *ftype = inst->_type->as_function_type();
- assert(ftype != (CPPFunctionType *)NULL);
- if (ftype->_flags & (CPPFunctionType::F_destructor |
- CPPFunctionType::F_move_constructor |
- CPPFunctionType::F_copy_constructor)) {
- // User-provided destructors and copy/move constructors are not trivial.
- return false;
- }
- if ((ftype->_flags & CPPFunctionType::F_constructor) != 0) {
- if (ftype->_parameters->_parameters.size() == 0 &&
- !ftype->_parameters->_includes_ellipsis) {
- // Same for the default constructor.
- return false;
- }
- // The presence of a non-default constructor makes the class not
- // default-constructible.
- is_default_constructible = false;
- }
- if (fgroup->_name == "operator =") {
- // Or assignment operators.
- return false;
- }
- }
- }
- // Finally, the class must be default-constructible.
- return is_default_constructible;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::check_virtual
- // Access: Public
- // Description: Ensures all functions are correctly marked with the
- // "virtual" flag if they are truly virtual by virtue of
- // inheritance, rather than simply being labeled
- // virtual.
- //
- // This also sets the CPPInstance::SC_inherited_virtual
- // flags on those virtual methods that override a
- // virtual method defined in a parent class (as opposed
- // to those that appear for this first time in this
- // class). It is sometimes useful to know whether a
- // given virtual method represents the first time that
- // particular method appears.
- //
- // The return value is true if this class defines or
- // inherits any virtual methods (and thus requires a
- // virtual function pointer), or false otherwise.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- check_virtual() {
- VFunctions funcs;
- get_virtual_funcs(funcs);
- return !funcs.empty();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::is_fully_specified
- // Access: Public, Virtual
- // Description: Returns true if this declaration is an actual,
- // factual declaration, or false if some part of the
- // declaration depends on a template parameter which has
- // not yet been instantiated.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- is_fully_specified() const {
- if (_scope != NULL && !_scope->is_fully_specified()) {
- return false;
- }
- return CPPType::is_fully_specified();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::is_incomplete
- // Access: Public, Virtual
- // Description: Returns true if the type has not yet been fully
- // specified, false if it has.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- is_incomplete() const {
- return _incomplete;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::get_destructor
- // Access: Public
- // Description: Returns the destructor defined for the struct type,
- // if any, or NULL if no destructor is found.
- ////////////////////////////////////////////////////////////////////
- CPPInstance *CPPStructType::
- get_destructor() const {
- // Iterate through all the functions that begin with '~' until we
- // find one that claims to be a destructor. In theory, there should
- // only be one such function.
- CPPScope::Functions::const_iterator fi;
- fi = _scope->_functions.lower_bound("~");
- while (fi != _scope->_functions.end() &&
- (*fi).first[0] == '~') {
- CPPFunctionGroup *fgroup = (*fi).second;
- CPPFunctionGroup::Instances::const_iterator ii;
- for (ii = fgroup->_instances.begin();
- ii != fgroup->_instances.end();
- ++ii) {
- CPPInstance *inst = (*ii);
- assert(inst->_type != (CPPType *)NULL);
- CPPFunctionType *ftype = inst->_type->as_function_type();
- assert(ftype != (CPPFunctionType *)NULL);
- if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) {
- return inst;
- }
- }
- ++fi;
- }
- return (CPPInstance *)NULL;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::instantiate
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPDeclaration *CPPStructType::
- instantiate(const CPPTemplateParameterList *actual_params,
- CPPScope *current_scope, CPPScope *global_scope,
- CPPPreprocessor *error_sink) const {
- // I *think* this assertion is no longer valid. Who knows.
- // assert(!_incomplete);
- if (_scope == NULL) {
- if (error_sink != NULL) {
- error_sink->warning("Ignoring template parameters for class " +
- get_local_name());
- }
- return (CPPDeclaration *)this;
- }
- CPPScope *scope =
- _scope->instantiate(actual_params, current_scope, global_scope, error_sink);
- if (scope->get_struct_type()->get_scope() != scope) {
- // Hmm, this type seems to be not completely defined. We must be
- // in the middle of recursively instantiating the scope. Thus, we
- // don't yet know what its associated struct type will be.
- // Postpone the evaluation of this type.
- CPPIdentifier *ident = new CPPIdentifier(get_fully_scoped_name(), _file);
- return CPPType::new_type(new CPPTBDType(ident));
- }
- CPPType *result = scope->get_struct_type();
- result = CPPType::new_type(result);
- if (result != (CPPType *)this) {
- // This really means the method ought to be non-const. But I'm
- // too lazy to propagate this change all the way back right now,
- // so this hack is here.
- ((CPPStructType *)this)->_instantiations.insert(result);
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::substitute_decl
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPDeclaration *CPPStructType::
- substitute_decl(CPPDeclaration::SubstDecl &subst,
- CPPScope *current_scope, CPPScope *global_scope) {
- SubstDecl::const_iterator si = subst.find(this);
- if (si != subst.end()) {
- assert((*si).second != NULL);
- return (*si).second;
- }
- if (_incomplete) {
- // We haven't finished defining the class yet.
- return this;
- }
- if (_subst_decl_recursive_protect) {
- // We're already executing this block; we'll have to return a
- // proxy to the type which we'll define later.
- CPPTypeProxy *proxy = new CPPTypeProxy;
- _proxies.push_back(proxy);
- assert(proxy != NULL);
- return proxy;
- }
- _subst_decl_recursive_protect = true;
- CPPStructType *rep = new CPPStructType(*this);
- if (_ident != NULL) {
- rep->_ident =
- _ident->substitute_decl(subst, current_scope, global_scope);
- }
- if (_scope != NULL) {
- rep->_scope =
- _scope->substitute_decl(subst, current_scope, global_scope);
- if (rep->_scope != _scope) {
- rep->_scope->set_struct_type(rep);
- // If we just instantiated a template scope, write the template
- // parameters into our identifier.
- CPPScope *pscope = rep->_scope->get_parent_scope();
- if (pscope != (CPPScope *)NULL &&
- pscope->_name.has_templ()) {
- // If the struct name didn't have an explicit template
- // reference before, now it does.
- if (!_ident->_names.empty() && !_ident->_names.back().has_templ()) {
- if (rep->is_template()) {
- rep->_template_scope = (CPPTemplateScope *)NULL;
- CPPNameComponent nc(get_simple_name());
- nc.set_templ(pscope->_name.get_templ());
- rep->_ident = new CPPIdentifier(nc, _file);
- }
- }
- }
- }
- }
- bool unchanged =
- (rep->_ident == _ident && rep->_scope == _scope);
- for (int i = 0; i < (int)_derivation.size(); ++i) {
- rep->_derivation[i]._base =
- _derivation[i]._base->substitute_decl(subst, current_scope, global_scope)->as_type();
- if (rep->_derivation[i]._base != _derivation[i]._base) {
- unchanged = false;
- }
- }
- if (unchanged) {
- delete rep;
- rep = this;
- }
- subst.insert(SubstDecl::value_type(this, rep));
- _subst_decl_recursive_protect = false;
- // Now fill in all the proxies we created for our recursive
- // references.
- Proxies::iterator pi;
- for (pi = _proxies.begin(); pi != _proxies.end(); ++pi) {
- (*pi)->_actual_type = rep;
- }
- assert(rep != NULL);
- rep = CPPType::new_type(rep)->as_struct_type();
- assert(rep != NULL);
- if (rep != this) {
- _instantiations.insert(rep);
- }
- return rep;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::output
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CPPStructType::
- output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
- if (!complete && _ident != NULL) {
- // If we have a name, use it.
- if (cppparser_output_class_keyword) {
- out << _type << " ";
- }
- out << _ident->get_local_name(scope);
- if (is_template()) {
- CPPTemplateScope *tscope = get_template_scope();
- tscope->_parameters.output(out, scope);
- }
- } else {
- if (is_template()) {
- get_template_scope()->_parameters.write_formal(out, scope);
- indent(out, indent_level);
- }
- if (_ident != NULL) {
- out << _type << " " << _ident->get_local_name(scope);
- } else {
- out << _type;
- }
- // Show any derivation we may have
- if (!_derivation.empty()) {
- Derivation::const_iterator di = _derivation.begin();
- out << ": " << *di;
- ++di;
- while (di != _derivation.end()) {
- out << ", " << *di;
- ++di;
- }
- }
- out << " {\n";
- _scope->write(out, indent_level + 2, _scope);
- indent(out, indent_level) << "}";
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::get_subtype
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPDeclaration::SubType CPPStructType::
- get_subtype() const {
- return ST_struct;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::as_struct_type
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- CPPStructType *CPPStructType::
- as_struct_type() {
- return this;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::get_virtual_funcs
- // Access: Public
- // Description: Fills funcs up with a list of all the virtual
- // function declarations (pure-virtual or otherwise)
- // defined at or above this class. This is used to
- // determine which functions in a given class are
- // actually virtual, since a function is virtual whose
- // parent class holds a virtual function by the same
- // name, whether or not it is actually declared virtual
- // in the derived class.
- ////////////////////////////////////////////////////////////////////
- void CPPStructType::
- get_virtual_funcs(VFunctions &funcs) const {
- // First, get all the virtual funcs from our parents.
- Derivation::const_iterator di;
- for (di = _derivation.begin(); di != _derivation.end(); ++di) {
- VFunctions vf;
- CPPStructType *base = (*di)._base->as_struct_type();
- if (base != NULL) {
- base->get_virtual_funcs(vf);
- funcs.splice(funcs.end(), vf);
- }
- }
- // Now look for matching functions in this class that we can now
- // infer are virtual.
- VFunctions::iterator vfi, vfnext;
- vfi = funcs.begin();
- while (vfi != funcs.end()) {
- vfnext = vfi;
- ++vfnext;
- CPPInstance *inst = (*vfi);
- assert(inst->_type != (CPPType *)NULL);
- CPPFunctionType *base_ftype = inst->_type->as_function_type();
- assert(base_ftype != (CPPFunctionType *)NULL);
- if ((base_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
- // Match destructor-for-destructor; don't try to match
- // destructors up by name.
- CPPInstance *destructor = get_destructor();
- if (destructor != (CPPInstance *)NULL) {
- // It's a match! This destructor is virtual.
- funcs.erase(vfi);
- destructor->_storage_class |=
- (CPPInstance::SC_virtual | CPPInstance::SC_inherited_virtual);
- }
- } else {
- // Non-destructors we can try to match up by name.
- string fname = inst->get_local_name();
- CPPScope::Functions::const_iterator fi;
- fi = _scope->_functions.find(fname);
- if (fi != _scope->_functions.end()) {
- CPPFunctionGroup *fgroup = (*fi).second;
- // Look for a matching function amid this group.
- bool match_found = false;
- CPPFunctionGroup::Instances::const_iterator ii;
- for (ii = fgroup->_instances.begin();
- ii != fgroup->_instances.end() && !match_found;
- ++ii) {
- CPPInstance *new_inst = (*ii);
- assert(new_inst->_type != (CPPType *)NULL);
- CPPFunctionType *new_ftype = new_inst->_type->as_function_type();
- assert(new_ftype != (CPPFunctionType *)NULL);
- if (new_ftype->is_equivalent_function(*base_ftype)) {
- // It's a match! We now know it's virtual. Erase this
- // function from the list, so we can add it back in below.
- funcs.erase(vfi);
- match_found = true;
- // In fact, it's not only definitely virtual, but it's
- // *inherited* virtual, which means only that the
- // interface is defined in some parent class. Sometimes
- // this is useful to know.
- new_inst->_storage_class |=
- (CPPInstance::SC_virtual | CPPInstance::SC_inherited_virtual);
- }
- }
- }
- }
- vfi = vfnext;
- }
- // Finally, look for more virtual function definitions.
- CPPScope::Functions::const_iterator fi;
- for (fi = _scope->_functions.begin();
- fi != _scope->_functions.end();
- ++fi) {
- CPPFunctionGroup *fgroup = (*fi).second;
- CPPFunctionGroup::Instances::const_iterator ii;
- for (ii = fgroup->_instances.begin();
- ii != fgroup->_instances.end();
- ++ii) {
- CPPInstance *inst = (*ii);
- if ((inst->_storage_class & CPPInstance::SC_virtual) != 0) {
- // Here's a virtual function.
- funcs.push_back(inst);
- }
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::count_pure_virtual_funcs
- // Access: Public
- // Description: Fills funcs up with a list of all the pure virtual
- // function declarations defined at or above this class
- // that have not been given definitions.
- ////////////////////////////////////////////////////////////////////
- void CPPStructType::
- get_pure_virtual_funcs(VFunctions &funcs) const {
- // First, get all the virtual functions.
- VFunctions vfuncs;
- get_virtual_funcs(vfuncs);
- // Now traverse the list, getting out those functions that are pure
- // virtual.
- VFunctions::iterator vfi;
- for (vfi = vfuncs.begin(); vfi != vfuncs.end(); ++vfi) {
- CPPInstance *inst = (*vfi);
- if ((inst->_storage_class & CPPInstance::SC_pure_virtual) != 0) {
- funcs.push_back(inst);
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::is_equal
- // Access: Protected, Virtual
- // Description: Called by CPPDeclaration to determine whether this
- // type is equivalent to another type of the same type.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- is_equal(const CPPDeclaration *other) const {
- return CPPDeclaration::is_equal(other);
- /*
- const CPPStructType *ot = ((CPPDeclaration *)other)->as_struct_type();
- assert(ot != NULL);
- return this == ot ||
- (get_fully_scoped_name() == ot->get_fully_scoped_name());
- */
- }
- ////////////////////////////////////////////////////////////////////
- // Function: CPPStructType::is_less
- // Access: Protected, Virtual
- // Description: Called by CPPDeclaration to determine whether this
- // type should be ordered before another type of the
- // same type, in an arbitrary but fixed ordering.
- ////////////////////////////////////////////////////////////////////
- bool CPPStructType::
- is_less(const CPPDeclaration *other) const {
- return CPPDeclaration::is_less(other);
- /*
- const CPPStructType *ot = ((CPPDeclaration *)other)->as_struct_type();
- assert(ot != NULL);
- if (this == ot) {
- return false;
- }
- return
- (get_fully_scoped_name() < ot->get_fully_scoped_name());
- */
- }
|