From c0957cfe1c73ecb6c96314e45e7d29b4199b20d6 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 31 Aug 2012 10:03:45 +0200 Subject: Add support for virtual data members New test: common/virtual. --- odb/semantics/class.cxx | 71 ++++++++++++++++++++++++++++++++++++ odb/semantics/class.hxx | 13 +++++++ odb/semantics/elements.cxx | 84 ++++++++++++++++++++++++++++++++++++++----- odb/semantics/elements.hxx | 59 ++++++++++++++++++++++++------ odb/semantics/fundamental.hxx | 10 ++++++ odb/semantics/namespace.cxx | 70 ++++++++++++++++++++++++++++++++++++ odb/semantics/namespace.hxx | 24 +++++++++++++ 7 files changed, 312 insertions(+), 19 deletions(-) (limited to 'odb/semantics') diff --git a/odb/semantics/class.cxx b/odb/semantics/class.cxx index 864a96e..e9e6610 100644 --- a/odb/semantics/class.cxx +++ b/odb/semantics/class.cxx @@ -39,6 +39,77 @@ namespace semantics return CLASSTYPE_PURE_VIRTUALS (tree_node ()); } + names* class_:: + lookup (string const& name, + type_id const& ti, + unsigned int flags, + bool* ph) const + { + bool h (false); + bool& rh (ph != 0 ? *ph : h); + + names* r (scope::lookup (name, ti, flags | exclude_outer, &rh)); + + if (r != 0) + return r; + + // If we found a name but the types didn't match, then bail out + // unless we want hidden names. + // + if (rh && (flags & include_hidden) == 0) + return 0; + + // Look in the base classes unless requested not to. For the name + // lookup purposes, bases can be viewed as a parallel set of outer + // scopes that are searched after the class scope and before any + // real outer scope. Interestingly, outer scopes of bases are not + // considered during this lookup, only their bases. + // + if ((flags & exclude_base) == 0) + { + // Being hidden in one base doesn't mean it is also hidden in the + // other. Normally that would be an ambiguous lookup, but we use + // relaxed rules. + // + bool any_h (false); // Indicates whether any base hides the name. + + for (inherits_iterator i (inherits_begin ()); i != inherits_end (); ++i) + { + bool h (false); // Indicates whether this base hides the name. + names* br (i->base ().lookup (name, ti, flags | exclude_outer, &h)); + any_h = any_h || h; + + if (br != 0) + { + if (r != 0) + throw ambiguous (*r, *br); + + r = br; + + if (h) + rh = true; + } + } + + if (r != 0) + return r; + + if (any_h) + { + rh = true; + if ((flags & include_hidden) == 0) + return 0; + } + } + + // Look in the outer scope unless requested not to. + // + if ((flags & exclude_outer) == 0) + return scope ().lookup (name, ti, flags, &rh); + + return 0; + } + // type info // namespace diff --git a/odb/semantics/class.hxx b/odb/semantics/class.hxx index b9f8f34..dc30da2 100644 --- a/odb/semantics/class.hxx +++ b/odb/semantics/class.hxx @@ -97,6 +97,19 @@ namespace semantics abstract () const; public: + // When doing lookup in class scope, take into account bases. + // + static unsigned int const exclude_base = 0x04; // Exclude base classes. + + virtual names* + lookup (string const& name, + type_id const&, + unsigned int flags = 0, + bool* hidden = 0) const; + + using scope::lookup; + + public: class_ (path const&, size_t line, size_t column, tree); void diff --git a/odb/semantics/elements.cxx b/odb/semantics/elements.cxx index ddae187..367ccbd 100644 --- a/odb/semantics/elements.cxx +++ b/odb/semantics/elements.cxx @@ -9,8 +9,11 @@ #include #include +#include #include +using namespace std; + namespace semantics { // access @@ -319,6 +322,79 @@ namespace semantics return i != iterator_map_.end () ? i->second : names_.end (); } + static bool + is_base (type_id const& b, compiler::type_info const& d) + { + using compiler::type_info; + + for (type_info::base_iterator i (d.begin_base ()); + i != d.end_base (); ++i) + { + type_info const& ti (i->type_info ()); + + if (b == ti.type_id () || is_base (b, ti)) + return true; + } + + return false; + } + + names* scope:: + lookup (string const& name, + type_id const& ti, + unsigned int flags, + bool* hidden) const + { + names_iterator_pair p (find (name)); + names* r (0); + + for (names_const_iterator i (p.first); i != p.second; ++i) + { + type_id const& xti (typeid (i->named ())); + + // If types are equal, then we found a match. Also check if ti is + // a base type of xti. + // + if (xti == ti || is_base (ti, compiler::lookup (xti))) + { + if (r != 0) + { + // If both are namespaces, then the one is just an extension + // of the other. + // + if (!(r->named ().is_a () && + i->named ().is_a ())) + throw ambiguous (*r, *i); + } + else + r = &*i; + } + } + + if (r != 0) + return r; + + // If we found a name but the types didn't match, then bail out + // unless we want hidden names. + // + if (p.first != p.second) + { + if (hidden != 0) + *hidden = true; + + if ((flags & include_hidden) == 0) + return 0; + } + + // Look in the outer scope unless requested not to or if this is + // the global scope. + // + if ((flags & exclude_outer) == 0 && !global_scope ()) + return scope ().lookup (name, ti, flags, hidden); + + return 0; + } + void scope:: add_edge_left (names& e) { @@ -443,14 +519,6 @@ namespace semantics insert (ti); } - // virtual_data_member - // - { - type_info ti (typeid (virtual_data_member)); - ti.add_base (typeid (data_member)); - insert (ti); - } - // unsupported_type // { diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx index c9aa00e..137fbda 100644 --- a/odb/semantics/elements.hxx +++ b/odb/semantics/elements.hxx @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ namespace semantics using container::graph; using container::pointer_iterator; + using compiler::type_id; using compiler::context; // @@ -501,6 +503,24 @@ namespace semantics }; + // Ambiguous name lookup exception. + // + struct ambiguous + { + ambiguous (names& f, names& s): first (f), second (s) {} + names& first; + names& second; + }; + + // Unresolved name lookup exception. + // + struct unresolved + { + unresolved (string const& n, bool tm): name (n), type_mismatch (tm) {} + string name; + bool type_mismatch; // True if the name resolved but types didn't match. + }; + // // class scope: public virtual nameable @@ -555,12 +575,40 @@ namespace semantics return names_.end (); } + // Find a name in this scope. + // + public: virtual names_iterator_pair find (string const& name) const; names_iterator find (names&); + // Lookup a name of the specified type in this scope and, if not + // found, in outer scopes. + // + public: + static unsigned int const exclude_outer = 0x01; // Exclude outer scopes. + static unsigned int const include_hidden = 0x02; // Include hidden names. + + virtual names* + lookup (string const& name, + type_id const&, + unsigned int flags = 0, + bool* hidden = 0) const; + + template + T& + lookup (string const& name, unsigned int flags = 0) const + { + bool hidden (false); + + if (names* n = lookup (name, typeid (T), flags, &hidden)) + return dynamic_cast (n->named ()); + + throw unresolved (name, hidden); + } + public: scope (path const& file, size_t line, size_t column, tree tn) : node (file, line, column, tn) @@ -757,17 +805,6 @@ namespace semantics } }; - // Virtual data member (extension to the standard C++ model). - // - class virtual_data_member: public data_member - { - public: - virtual_data_member (path const& file, size_t line, size_t column) - : node (file, line, column, 0) - { - } - }; - // Unsupported type. // class unsupported_type: public type diff --git a/odb/semantics/fundamental.hxx b/odb/semantics/fundamental.hxx index 291d73c..879837c 100644 --- a/odb/semantics/fundamental.hxx +++ b/odb/semantics/fundamental.hxx @@ -46,6 +46,16 @@ namespace semantics fund_wchar (tree tn): node (path (""), 0, 0, tn) {} }; + struct fund_char16: fund_type + { + fund_char16 (tree tn): node (path (""), 0, 0, tn) {} + }; + + struct fund_char32: fund_type + { + fund_char32 (tree tn): node (path (""), 0, 0, tn) {} + }; + struct fund_signed_char: fund_type { fund_signed_char (tree tn): node (path (""), 0, 0, tn) {} diff --git a/odb/semantics/namespace.cxx b/odb/semantics/namespace.cxx index 9906219..257385e 100644 --- a/odb/semantics/namespace.cxx +++ b/odb/semantics/namespace.cxx @@ -19,6 +19,76 @@ namespace semantics { } + names* namespace_:: + lookup (string const& name, + type_id const& ti, + unsigned int flags, + bool* hidden) const + { + if (original_ != 0) + return original_->lookup (name, ti, flags, hidden); + + // Being hidden in one namespace doesn't mean it is also hidden in + // the other. Normally that would be an ambiguous lookup, but we use + // relaxed rules. + // + bool h (false); // Indicates whether this namespace hides the name. + bool any_h (false); // Indicates whether any namespace hides the name. + + names* r (scope::lookup (name, ti, flags | exclude_outer, &h)); + any_h = any_h || h; + + if (r != 0 && h && hidden != 0) + *hidden = true; + + for (extensions_iterator i (extensions_begin ()); + i != extensions_end (); + ++i) + { + h = false; + names* er ((*i)->scope::lookup (name, ti, flags | exclude_outer, &h)); + any_h = any_h || h; + + if (er != 0) + { + if (r != 0) + { + // If both are namespaces, then the one is just an extension + // of the other. + // + if (!(r->named ().is_a () && + er->named ().is_a ())) + throw ambiguous (*r, *er); + } + else + r = er; + + if (h && hidden != 0) + *hidden = true; + } + } + + if (r != 0) + return r; + + if (any_h) + { + if (hidden != 0) + *hidden = true; + + if ((flags & include_hidden) == 0) + return 0; + } + + // Look in the outer scope unless requested not to or if this is + // the global scope. + // + if ((flags & exclude_outer) == 0 && !global_scope ()) + return scope ().lookup (name, ti, flags, hidden); + + return 0; + } + // type info // namespace diff --git a/odb/semantics/namespace.hxx b/odb/semantics/namespace.hxx index a4ead38..df48e437 100644 --- a/odb/semantics/namespace.hxx +++ b/odb/semantics/namespace.hxx @@ -5,12 +5,16 @@ #ifndef ODB_SEMANTICS_NAMESPACE_HXX #define ODB_SEMANTICS_NAMESPACE_HXX +#include + #include namespace semantics { class namespace_: public scope { + typedef std::vector extensions_type; + public: bool extension () const @@ -28,9 +32,28 @@ namespace semantics original (namespace_& ns) { original_ = &ns; + ns.extensions_.push_back (this); } public: + typedef extensions_type::const_iterator extensions_iterator; + + extensions_iterator + extensions_begin () const {return extensions_.begin ();} + + extensions_iterator + extensions_end () const {return extensions_.end ();} + + public: + virtual names* + lookup (string const& name, + type_id const&, + unsigned int flags = 0, + bool* hidden = 0) const; + + using scope::lookup; + + public: namespace_ (path const&, size_t line, size_t column, tree); // Resolve conflict between scope::scope and nameable::scope. @@ -42,6 +65,7 @@ namespace semantics private: namespace_* original_; + extensions_type extensions_; }; } -- cgit v1.1