| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /**
- * 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."
- *
- * @file cppInstance.cxx
- * @author drose
- * @date 1999-10-19
- */
- #include "cppInstance.h"
- #include "cppInstanceIdentifier.h"
- #include "cppIdentifier.h"
- #include "cppTemplateScope.h"
- #include "cppFunctionType.h"
- #include "cppSimpleType.h"
- #include "cppExpression.h"
- #include "cppPreprocessor.h"
- #include "cppParameterList.h"
- #include "cppReferenceType.h"
- #include "cppConstType.h"
- #include "indent.h"
- #include <algorithm>
- using std::string;
- /**
- *
- */
- CPPInstance::
- CPPInstance(CPPType *type, const string &name, int storage_class) :
- CPPDeclaration(CPPFile()),
- _type(type),
- _ident(new CPPIdentifier(name)),
- _storage_class(storage_class),
- _bit_width(-1)
- {
- _initializer = nullptr;
- }
- /**
- *
- */
- CPPInstance::
- CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
- CPPDeclaration(CPPFile()),
- _type(type),
- _ident(ident),
- _storage_class(storage_class),
- _bit_width(-1)
- {
- _initializer = nullptr;
- }
- /**
- * Constructs a new CPPInstance object that defines a variable of the
- * indicated type according to the type and the InstanceIdentifier. The
- * InstanceIdentifier pointer is deallocated.
- */
- CPPInstance::
- CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
- const CPPFile &file) :
- CPPDeclaration(file)
- {
- _type = ii->unroll_type(type);
- _ident = ii->_ident;
- _attributes = ii->_attributes;
- ii->_ident = nullptr;
- _storage_class = storage_class;
- _initializer = nullptr;
- if (ii->_bit_width != nullptr) {
- CPPExpression::Result result = ii->_bit_width->evaluate();
- if (result._type != CPPExpression::RT_error) {
- _bit_width = ii->_bit_width->evaluate().as_integer();
- } else {
- _bit_width = -1;
- }
- } else {
- _bit_width = -1;
- }
- CPPParameterList *params = ii->get_initializer();
- if (params != nullptr) {
- // In this case, the instance has a parameter-list initializer, e.g.: int
- // foo(0); We really should save this initializer in the instance object.
- // But we don't for now, since no one really cares about initializers
- // anyway.
- }
- if (ii->_packed) {
- _storage_class |= SC_parameter_pack;
- }
- delete ii;
- }
- /**
- *
- */
- CPPInstance::
- CPPInstance(const CPPInstance ©) :
- CPPDeclaration(copy),
- _type(copy._type),
- _ident(copy._ident),
- _initializer(copy._initializer),
- _storage_class(copy._storage_class),
- _bit_width(copy._bit_width)
- {
- assert(_type != nullptr);
- }
- /**
- *
- */
- CPPInstance::
- ~CPPInstance() {
- // Can't delete the identifier. Don't try.
- }
- /**
- * Constructs and returns a new CPPInstance object that corresponds to a
- * function prototype declaration for a typecast method, whose return type is
- * implicit in the identifier type.
- */
- CPPInstance *CPPInstance::
- make_typecast_function(CPPInstance *inst, CPPIdentifier *ident,
- CPPParameterList *parameters, int function_flags) {
- CPPType *type = CPPType::new_type(inst->_type);
- delete inst;
- function_flags |= (int)CPPFunctionType::F_operator_typecast;
- CPPType *ft =
- CPPType::new_type(new CPPFunctionType(type, parameters, function_flags));
- return new CPPInstance(ft, ident);
- }
- /**
- *
- */
- bool CPPInstance::
- operator == (const CPPInstance &other) const {
- if (_type != other._type) {
- return false;
- }
- if (_storage_class != other._storage_class) {
- return false;
- }
- if (_attributes != other._attributes) {
- return false;
- }
- // We *do* care about the identifier. We need to differentiate types of
- // function variables, among possibly other things, based on the identifier.
- if ((_ident == nullptr && other._ident != nullptr) ||
- (_ident != nullptr && other._ident == nullptr) ||
- (_ident != nullptr && other._ident != nullptr && *_ident != *other._ident))
- {
- return false;
- }
- // We similarly care about the initializer.
- if ((_initializer == nullptr && other._initializer != nullptr) ||
- (_initializer != nullptr && other._initializer == nullptr) ||
- (_initializer != nullptr && other._initializer != nullptr &&
- *_initializer != *other._initializer))
- {
- return false;
- }
- return true;
- }
- /**
- *
- */
- bool CPPInstance::
- operator != (const CPPInstance &other) const {
- return !operator == (other);
- }
- /**
- *
- */
- bool CPPInstance::
- operator < (const CPPInstance &other) const {
- if (_type != other._type) {
- return _type < other._type;
- }
- if (_storage_class != other._storage_class) {
- return _storage_class < other._storage_class;
- }
- if (_attributes != other._attributes) {
- return _attributes < other._attributes;
- }
- // We *do* care about the identifier. We need to differentiate types of
- // function variables, among possibly other things, based on the identifier.
- if ((_ident == nullptr && other._ident != nullptr) ||
- (_ident != nullptr && other._ident == nullptr) ||
- (_ident != nullptr && other._ident != nullptr && *_ident != *other._ident))
- {
- if (_ident == nullptr || other._ident == nullptr) {
- return _ident < other._ident;
- }
- return *_ident < *other._ident;
- }
- // We similarly care about the initializer.
- if ((_initializer == nullptr && other._initializer != nullptr) ||
- (_initializer != nullptr && other._initializer == nullptr) ||
- (_initializer != nullptr && other._initializer != nullptr &&
- *_initializer != *other._initializer))
- {
- if (_initializer == nullptr || other._initializer == nullptr) {
- return _initializer < other._initializer;
- }
- return *_initializer < *other._initializer;
- }
- return false;
- }
- /**
- * Sets the value of the expression that is used to initialize the variable,
- * or the default value for a parameter. If a non-null expression is set on a
- * function declaration, it implies that the function is pure virtual.
- */
- void CPPInstance::
- set_initializer(CPPExpression *initializer) {
- if (_type->as_function_type() != nullptr) {
- // This is a function declaration.
- _storage_class &= ~(SC_pure_virtual | SC_defaulted | SC_deleted);
- _initializer = nullptr;
- if (initializer != nullptr) {
- if (initializer->_type == CPPExpression::T_integer) { // = 0
- _storage_class |= SC_pure_virtual;
- } else if (initializer->_type == CPPExpression::T_default) {
- _storage_class |= SC_defaulted;
- } else if (initializer->_type == CPPExpression::T_delete) {
- _storage_class |= SC_deleted;
- }
- }
- } else {
- _initializer = initializer;
- }
- }
- /**
- * Sets the number of bytes to align this instance to.
- */
- void CPPInstance::
- set_alignment(int align) {
- _attributes.add_alignas(align);
- }
- /**
- * Sets the expression that is used to determine the required alignment for
- * the variable. This should be a constant expression, but we don't presently
- * verify that it is.
- */
- void CPPInstance::
- set_alignment(CPPExpression *const_expr) {
- _attributes.add_alignas(const_expr);
- }
- /**
- *
- */
- bool CPPInstance::
- is_scoped() const {
- if (_ident == nullptr) {
- return false;
- } else {
- return _ident->is_scoped();
- }
- }
- /**
- *
- */
- CPPScope *CPPInstance::
- get_scope(CPPScope *current_scope, CPPScope *global_scope,
- CPPPreprocessor *error_sink) const {
- if (_ident == nullptr) {
- return current_scope;
- } else {
- return _ident->get_scope(current_scope, global_scope, error_sink);
- }
- }
- /**
- *
- */
- string CPPInstance::
- get_simple_name() const {
- if (_ident == nullptr) {
- return "";
- } else {
- return _ident->get_simple_name();
- }
- }
- /**
- *
- */
- string CPPInstance::
- get_local_name(CPPScope *scope) const {
- if (_ident == nullptr) {
- return "";
- } else {
- return _ident->get_local_name(scope);
- }
- }
- /**
- *
- */
- string CPPInstance::
- get_fully_scoped_name() const {
- if (_ident == nullptr) {
- return "";
- } else {
- return _ident->get_fully_scoped_name();
- }
- }
- /**
- * If this is a function type instance, checks whether the function name
- * matches the class name (or ~name), and if so, flags it as a constructor,
- * destructor or assignment operator
- */
- void CPPInstance::
- check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) {
- CPPScope *scope = get_scope(current_scope, global_scope);
- if (scope == nullptr) {
- scope = current_scope;
- }
- CPPFunctionType *func = _type->as_function_type();
- if (func != nullptr && scope != nullptr) {
- string method_name = get_local_name(scope);
- string class_name = scope->get_local_name();
- if (!method_name.empty() && !class_name.empty()) {
- // Check either a constructor or assignment operator.
- if (method_name == class_name || method_name == "operator =") {
- CPPType *void_type = CPPType::new_type
- (new CPPSimpleType(CPPSimpleType::T_void));
- int flags = func->_flags;
- if (method_name == class_name) {
- flags |= CPPFunctionType::F_constructor;
- }
- CPPParameterList *params = func->_parameters;
- if (params->_parameters.size() == 1 && !params->_includes_ellipsis) {
- CPPType *param_type = params->_parameters[0]->_type;
- CPPReferenceType *ref_type = param_type->as_reference_type();
- if (ref_type != nullptr) {
- param_type = ref_type->_pointing_at->remove_cv();
- if (class_name == param_type->get_simple_name()) {
- if (flags & CPPFunctionType::F_constructor) {
- if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
- flags |= CPPFunctionType::F_move_constructor;
- } else {
- flags |= CPPFunctionType::F_copy_constructor;
- }
- } else {
- if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
- flags |= CPPFunctionType::F_move_assignment_operator;
- } else {
- flags |= CPPFunctionType::F_copy_assignment_operator;
- }
- }
- }
- }
- }
- _type = CPPType::new_type
- (new CPPFunctionType(void_type, func->_parameters, flags));
- } else if (method_name == "~" + class_name) {
- CPPType *void_type = CPPType::new_type
- (new CPPSimpleType(CPPSimpleType::T_void));
- _type = CPPType::new_type
- (new CPPFunctionType(void_type, func->_parameters,
- func->_flags | CPPFunctionType::F_destructor));
- }
- }
- }
- }
- /**
- *
- */
- CPPDeclaration *CPPInstance::
- instantiate(const CPPTemplateParameterList *actual_params,
- CPPScope *current_scope, CPPScope *global_scope,
- CPPPreprocessor *error_sink) const {
- if (!is_template()) {
- if (error_sink != nullptr) {
- error_sink->warning("Ignoring template parameters for instance " +
- _ident->get_local_name());
- }
- return (CPPInstance *)this;
- }
- Instantiations::const_iterator ii;
- ii = _instantiations.find(actual_params);
- if (ii != _instantiations.end()) {
- // We've already instantiated this instance with these parameters. Return
- // that.
- return (*ii).second;
- }
- CPPTemplateScope *tscope = get_template_scope();
- CPPDeclaration::SubstDecl subst;
- actual_params->build_subst_decl(tscope->_parameters, subst,
- current_scope, global_scope);
- CPPInstance *inst =
- ((CPPInstance *)this)->substitute_decl(subst, current_scope, global_scope)
- ->as_instance();
- if (inst == this) {
- // Hmm, nothing to substitute. Make a new instance anyway, so we can
- // change the name.
- inst = new CPPInstance(*this);
- }
- assert(inst != nullptr);
- inst->_ident = inst->_ident->substitute_decl(subst, current_scope, global_scope);
- if (inst->_ident == _ident) {
- inst->_ident = new CPPIdentifier(*inst->_ident);
- }
- inst->_ident->_names.back().set_templ
- (new CPPTemplateParameterList(*actual_params));
- inst->_template_scope = nullptr;
- ((CPPInstance *)this)->_instantiations.insert(Instantiations::value_type(actual_params, inst));
- return inst;
- }
- /**
- * 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 CPPInstance::
- is_fully_specified() const {
- if (_ident != nullptr && !_ident->is_fully_specified()) {
- return false;
- }
- if (_initializer != nullptr && !_initializer->is_fully_specified()) {
- return false;
- }
- return CPPDeclaration::is_fully_specified() &&
- _type->is_fully_specified();
- }
- /**
- *
- */
- CPPDeclaration *CPPInstance::
- substitute_decl(CPPDeclaration::SubstDecl &subst,
- CPPScope *current_scope, CPPScope *global_scope) {
- CPPDeclaration *top =
- CPPDeclaration::substitute_decl(subst, current_scope, global_scope);
- if (top != this) {
- return top;
- }
- CPPInstance *rep = new CPPInstance(*this);
- CPPDeclaration *new_type =
- _type->substitute_decl(subst, current_scope, global_scope);
- rep->_type = new_type->as_type();
- if (rep->_type == nullptr) {
- rep->_type = _type;
- }
- if (_initializer != nullptr) {
- rep->_initializer =
- _initializer->substitute_decl(subst, current_scope, global_scope)
- ->as_expression();
- }
- if (rep->_type == _type &&
- rep->_initializer == _initializer) {
- delete rep;
- rep = this;
- }
- subst.insert(SubstDecl::value_type(this, rep));
- return rep;
- }
- /**
- *
- */
- void CPPInstance::
- output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const {
- output(out, indent_level, scope, complete, -1);
- }
- /**
- * The extra parameter comes into play only when we happen to be outputting a
- * function prototype. See CPPFunctionType::output().
- */
- void CPPInstance::
- output(std::ostream &out, int indent_level, CPPScope *scope, bool complete,
- int num_default_parameters) const {
- assert(_type != nullptr);
- if (_type->is_parameter_expr()) {
- // In this case, the whole thing is really an expression, and not an
- // instance at all. This can only happen if we parsed an instance
- // declaration while we thought we were parsing a function prototype.
- out << *_initializer;
- return;
- }
- if (is_template()) {
- get_template_scope()->_parameters.write_formal(out, scope);
- indent(out, indent_level);
- }
- if (!_attributes.is_empty()) {
- out << _attributes << " ";
- }
- if (_storage_class & SC_static) {
- out << "static ";
- }
- if (_storage_class & SC_extern) {
- out << "extern ";
- }
- if (_storage_class & SC_c_binding) {
- out << "\"C\" ";
- }
- if (_storage_class & SC_virtual) {
- out << "virtual ";
- }
- if (_storage_class & SC_inline) {
- out << "inline ";
- }
- if (_storage_class & SC_explicit) {
- out << "explicit ";
- }
- if (_storage_class & SC_register) {
- out << "register ";
- }
- if (_storage_class & SC_volatile) {
- out << "volatile ";
- }
- if (_storage_class & SC_mutable) {
- out << "mutable ";
- }
- if (_storage_class & SC_consteval) {
- out << "consteval ";
- }
- if (_storage_class & SC_constexpr) {
- out << "constexpr ";
- }
- if (_storage_class & SC_constinit) {
- out << "constinit ";
- }
- if (_storage_class & SC_thread_local) {
- out << "thread_local ";
- }
- string name;
- if (_ident != nullptr) {
- name = _ident->get_local_name(scope);
- }
- if (_storage_class & SC_parameter_pack) {
- name = "..." + name;
- }
- if (_type->as_function_type()) {
- _type->as_function_type()->
- output_instance(out, indent_level, scope, complete, "", name,
- num_default_parameters);
- }
- else {
- _type->output_instance(out, indent_level, scope, complete, "", name);
- }
- if (_bit_width != -1) {
- out << " : " << _bit_width;
- }
- if (_storage_class & SC_pure_virtual) {
- out << " = 0";
- }
- if (_storage_class & SC_defaulted) {
- out << " = default";
- }
- if (_storage_class & SC_deleted) {
- out << " = delete";
- }
- if (_initializer != nullptr) {
- out << " = " << *_initializer;
- }
- }
- /**
- *
- */
- CPPDeclaration::SubType CPPInstance::
- get_subtype() const {
- return ST_instance;
- }
- /**
- *
- */
- CPPInstance *CPPInstance::
- as_instance() {
- return this;
- }
|