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/context.hxx | 2 +- odb/lookup.cxx | 249 ++++++++++++++++++++++++- odb/lookup.hxx | 37 ++++ odb/parser.cxx | 152 ++++++++++++--- odb/pragma.cxx | 424 +++++++++++++++++++++++++++++++++--------- odb/pragma.hxx | 118 +++++++++++- odb/relational/processor.cxx | 325 ++++++++++++++++++-------------- odb/relational/source.cxx | 151 +++++++-------- odb/relational/source.hxx | 2 +- 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 +++ odb/traversal/elements.cxx | 20 -- odb/traversal/elements.hxx | 14 -- odb/validator.cxx | 97 ++++++---- 19 files changed, 1489 insertions(+), 433 deletions(-) diff --git a/odb/context.hxx b/odb/context.hxx index a24edee..3651344 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -162,7 +162,7 @@ typedef std::vector view_objects; // The view_alias_map does not contain entries for tables. // typedef std::map view_alias_map; -typedef std::map view_object_map; +typedef std::map view_object_map; // // diff --git a/odb/lookup.cxx b/odb/lookup.cxx index b3e0551..2190301 100644 --- a/odb/lookup.cxx +++ b/odb/lookup.cxx @@ -3,12 +3,120 @@ // license : GNU GPL v3; see accompanying LICENSE file #include +#include using namespace std; namespace lookup { - std::string + // Return canonical fundamental type name ( , e.g., + // short unsigned int) or empty string if it is not a fundamental type. + // Note that the type can still be invalid (e.g., unsigned float) so it + // needs to be resolved. + // + static string + parse_fundamental (cxx_lexer& l, + cpp_ttype& tt, + string& tl, + tree& tn, + cpp_ttype& ptt, + string& name) + { + bool + si (false), // signed + un (false), // unsigned + sh (false), // short + lo (false), // long + ll (false); // long long + + string type; + + for (; tt == CPP_KEYWORD; ptt = tt, tt = l.next (tl, &tn)) + { + if (!name.empty ()) + name += ' '; + name += tl; + + if (tl == "signed") + { + if (si || un) + throw invalid_name (); + + si = true; + } + else if (tl == "unsigned") + { + if (si || un) + throw invalid_name (); + + un = true; + } + else if (tl == "short") + { + if (sh || lo || ll) + throw invalid_name (); + + sh = true; + } + else if (tl == "long") + { + if (sh || ll) + throw invalid_name (); + + if (lo) + { + lo = false; + ll = true; + } + else + lo = true; + } + else if (tl == "bool" || + tl == "char" || + tl == "wchar_t" || + tl == "char16_t" || // C++11 + tl == "char32_t" || // C++11 + tl == "int" || + tl == "float" || + tl == "double") + { + if (!type.empty ()) + throw invalid_name (); + + type = tl; + } + else + break; + } + + if (type.empty () && (si || un || sh || lo || ll)) + type = "int"; // If type not specified, it defaults to int. + + if (type.empty ()) + return type; + + string r; + + if (sh) + r += "short "; + + if (lo) + r += "long "; + + if (ll) + r += "long long "; + + if (si && type == "char") + r += "signed "; + + if (un) + r += "unsigned "; + + r += type; + return r; + } + + string parse_scoped_name (cxx_lexer& l, cpp_ttype& tt, string& tl, tree& tn) { string name; @@ -18,12 +126,18 @@ namespace lookup name += "::"; tt = l.next (tl, &tn); } + else if (tt == CPP_KEYWORD) + { + cpp_ttype ptt; // Not used. + string t (parse_fundamental (l, tt, tl, tn, ptt, name)); + + if (!t.empty ()) + return name; + } while (true) { - // @@ We still need to handle fundamental types, e.g., unsigned int. - // - if (tt != CPP_NAME && tt != CPP_KEYWORD) + if (tt != CPP_NAME) throw invalid_name (); name += tl; @@ -63,15 +177,32 @@ namespace lookup ptt = tt; tt = l.next (tl, &tn); } + else if (tt == CPP_KEYWORD) + { + string t (parse_fundamental (l, tt, tl, tn, ptt, name)); + + if (!t.empty ()) + { + tree decl ( + lookup_qualified_name ( + global_namespace, get_identifier (t.c_str ()), true, false)); + + if (decl == error_mark_node) + throw unable_to_resolve (name, true); + + if (end_scope != 0) + *end_scope = global_namespace; + + return decl; + } + } while (true) { if (end_scope != 0) *end_scope = scope; - // @@ We still need to handle fundamental types, e.g., unsigned int. - // - if (tt != CPP_NAME && tt != CPP_KEYWORD) + if (tt != CPP_NAME) throw invalid_name (); name += tl; @@ -137,4 +268,108 @@ namespace lookup return scope; } + + semantics::node& + resolve_scoped_name (cxx_lexer& l, + cpp_ttype& tt, + string& tl, + tree& tn, + cpp_ttype& ptt, + semantics::scope& start_scope, + string& name, + semantics::type_id const& tid, + bool trailing_scope, + semantics::scope** end_scope) + { + bool first (true); + semantics::scope* scope (&start_scope); + + if (tt == CPP_SCOPE) + { + name += "::"; + for (; !scope->global_scope (); scope = &scope->scope_ ()) ; + first = false; + + ptt = tt; + tt = l.next (tl, &tn); + } + else if (tt == CPP_KEYWORD) + { + string t (parse_fundamental (l, tt, tl, tn, ptt, name)); + + if (!t.empty ()) + { + for (; !scope->global_scope (); scope = &scope->scope_ ()) ; + + if (end_scope != 0) + *end_scope = scope; + + return scope->lookup (t); + } + } + + semantics::names* r; + + for (;;) + { + if (end_scope != 0) + *end_scope = scope; + + if (tt != CPP_NAME) + throw invalid_name (); + + name += tl; + string n (tl); + ptt = tt; + tt = l.next (tl, &tn); + + bool last (true); + if (tt == CPP_SCOPE) + { + // If trailing scope names are allowed, then we also need to + // check what's after the scope. + // + if (trailing_scope) + { + ptt = tt; + tt = l.next (tl, &tn); + + if (tt == CPP_NAME) + last = false; + } + else + last = false; + } + + // If this is the first component in the name, then also search the + // outer scopes. + // + bool hidden (false); + r = scope->lookup ( + n, + (last ? tid : typeid (semantics::scope)), + (first ? 0 : semantics::scope::exclude_outer) | + (last ? semantics::scope::include_hidden : 0), + (last ? &hidden : 0)); + + if (r == 0) + throw semantics::unresolved (name, hidden); + + if (last) + break; + + scope = &dynamic_cast (r->named ()); + first = false; + + name += "::"; + + if (!trailing_scope) + { + ptt = tt; + tt = l.next (tl, &tn); + } + } + + return r->named (); + } } diff --git a/odb/lookup.hxx b/odb/lookup.hxx index c207543..9e63c2a 100644 --- a/odb/lookup.hxx +++ b/odb/lookup.hxx @@ -10,6 +10,7 @@ #include #include +#include namespace lookup { @@ -45,6 +46,9 @@ namespace lookup // In this case token will be and // ptt will be CPP_SCOPE. // + // The names are appended to the 'name' variable as they are + // being resolved. + // tree resolve_scoped_name (cxx_lexer&, cpp_ttype&, @@ -56,6 +60,39 @@ namespace lookup bool is_type, bool trailing_scope = false, tree* end_scope = 0); + + // The same but using semantic graph instead of GCC tree. Also + // throws semantics::unresolved instead of unable_to_resolve. + // + semantics::node& + resolve_scoped_name (cxx_lexer&, + cpp_ttype&, + std::string& tl, // Token literal. + tree& tn, // Token node. + cpp_ttype& ptt, // Previous token type. + semantics::scope& start_scope, + std::string& name, + semantics::type_id const&, + bool trailing_scope = false, + semantics::scope** end_scope = 0); + + template + T& + resolve_scoped_name (cxx_lexer& l, + cpp_ttype& tt, + std::string& tl, // Token literal. + tree& tn, // Token node. + cpp_ttype& ptt, // Previous token type. + semantics::scope& start_scope, + std::string& name, + bool trailing_scope = false, + semantics::scope** end_scope = 0) + { + return dynamic_cast ( + resolve_scoped_name ( + l, tt, tl, tn, ptt, + start_scope, name, typeid (T), trailing_scope, end_scope)); + } } #endif // ODB_LOOKUP_HXX diff --git a/odb/parser.cxx b/odb/parser.cxx index 18bb4a3..b26c985 100644 --- a/odb/parser.cxx +++ b/odb/parser.cxx @@ -32,19 +32,27 @@ public: private: typedef semantics::access access; - // Extended GGC tree declaration that is either a tree node or a - // pragma. If this declaration is a pragma, then the assoc flag - // indicated whether this pragma has been associated with a - // declaration. + // Extended GGC tree declaration that is either a GCC tree + // declaration, a virtual declaration, or a pragma. If it is + // a pragma, then the assoc flag indicated whether this pragma + // has been associated with a declaration. Otherwise, the assoc + // flag indicates whether pragmas have been associated with this + // declaration (we use this to ignore certain declarations for + // pragma association purposes, e.g., the anonymous type in + // struct {...} m_). // struct tree_decl { tree decl; + virt_declaration const* vdecl; pragma const* prag; mutable bool assoc; // Allow modification via std::set iterator. - tree_decl (tree d): decl (d), prag (0) {} - tree_decl (pragma const& p): decl (0), prag (&p), assoc (false) {} + tree_decl (tree d): decl (d), vdecl (0), prag (0), assoc (false) {} + tree_decl (virt_declaration const& d) + : decl (0), vdecl (&d), prag (0), assoc (false) {} + tree_decl (pragma const& p) + : decl (0), vdecl (0), prag (&p), assoc (false) {} bool operator< (tree_decl const& y) const; @@ -116,7 +124,7 @@ private: // Process positioned and named pragmas. // void - process_pragmas (tree, + process_pragmas (declaration const&, node&, string const& name, decl_set::const_iterator begin, @@ -126,7 +134,7 @@ private: // Process named pragmas only. // void - process_named_pragmas (tree, node&); + process_named_pragmas (declaration const&, node&); void diagnose_unassoc_pragmas (decl_set const&); @@ -180,8 +188,16 @@ private: bool parser::impl::tree_decl:: operator< (tree_decl const& y) const { - location_t xloc (decl ? DECL_SOURCE_LOCATION (decl) : prag->loc); - location_t yloc (y.decl ? DECL_SOURCE_LOCATION (y.decl) : y.prag->loc); + location_t xloc ( + decl != 0 + ? DECL_SOURCE_LOCATION (decl) + : (vdecl != 0 ? vdecl->loc : prag->loc)); + + location_t yloc ( + y.decl != 0 + ? DECL_SOURCE_LOCATION (y.decl) + : (y.vdecl != 0 ? y.vdecl->loc : y.prag->loc)); + return xloc < yloc; } @@ -325,6 +341,15 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub) } } + // Add virtual declarations if any. + // + { + virt_declarations::const_iterator i (virt_declarations_.find (c)); + + if (i != virt_declarations_.end ()) + decls.insert (i->second.begin (), i->second.end ()); + } + // Add location pragmas if any. // { @@ -342,9 +367,71 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub) { // Skip pragmas. // - if (i->prag) + if (i->prag != 0) continue; + // Handle virtual declarations. + // + if (i->vdecl != 0) + { + virt_declaration const& vd (*i->vdecl); + + switch (vd.tree_code) + { + case FIELD_DECL: + { + // First check that it doesn't conflict with any of the real + // data members defined in this class. + // + tree d ( + lookup_qualified_name ( + c, get_identifier (vd.name.c_str ()), false, false)); + + if (d != error_mark_node && TREE_CODE (d) == FIELD_DECL) + { + error (vd.loc) << "virtual data member declaration '" << vd.name + << "' conflicts with a previous declaration" + << endl; + + location_t l (DECL_SOURCE_LOCATION (d)); + info (l) << "'" << vd.name << "' was previously declared here" + << endl; + + throw failed (); + } + + path file (LOCATION_FILE (vd.loc)); + size_t line (LOCATION_LINE (vd.loc)); + size_t clmn (LOCATION_COLUMN (vd.loc)); + + access a (access::public_); + + type& type_node (emit_type (vd.type, a, file, line, clmn)); + data_member& member_node ( + unit_->new_node (file, line, clmn, tree (0))); + + unit_->new_edge (*c_node, member_node, vd.name, a); + belongs& edge (unit_->new_edge (member_node, type_node)); + + // See if there is a name hint for this type. + // + if (names* hint = unit_->find_hint (vd.type)) + edge.hint (*hint); + + // Process pragmas that may be associated with this field. + // + process_pragmas (vd, member_node, vd.name, b, i, e); + break; + } + default: + { + assert (false); + break; + } + } + continue; + } + tree d (i->decl); switch (TREE_CODE (d)) @@ -438,6 +525,7 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub) } default: { + assert (false); break; } } @@ -657,6 +745,13 @@ parse (tree global_scope, path const& main_file) define_fund (boolean_type_node); define_fund (char_type_node); define_fund (wchar_type_node); + + if (ops_.std () == cxx_version::cxx11) + { + define_fund (char16_type_node); + define_fund (char32_type_node); + } + define_fund (signed_char_type_node); define_fund (unsigned_char_type_node); define_fund (short_integer_type_node); @@ -1992,47 +2087,48 @@ emit_type_name (tree type, bool direct) } void parser::impl:: -process_pragmas (tree t, +process_pragmas (declaration const& decl, node& node, string const& name, decl_set::const_iterator begin, decl_set::const_iterator cur, decl_set::const_iterator /*end*/) { - // First process the position pragmas by iterating backwards - // until we get to the preceding non-pragma declaration. + // First process the position pragmas by iterating backwards until + // we get to the preceding non-pragma declaration that has been + // associated. // pragma_set prags; if (cur != begin) { decl_set::const_iterator i (cur); - for (--i; i != begin && i->prag != 0; --i) ; - - // We may stop at pragma if j == b. - // - if (i->prag == 0) - ++i; + for (--i; i != begin && (i->prag != 0 || !i->assoc); --i) ; for (; i != cur; ++i) { + if (i->prag == 0) // Skip declarations. + continue; + assert (!i->assoc); - if (i->prag->check (t, name, i->prag->pragma_name, i->prag->loc)) + if (i->prag->check (decl, name, i->prag->pragma_name, i->prag->loc)) prags.insert (*i->prag); else - error_++; + error_++; // Diagnostic has already been issued. i->assoc = true; // Mark this pragma as associated. } + + cur->assoc = true; // Mark the declaration as associated. } - // Now see if there are any identifier pragmas for this decl. - // By doing this after handling the position pragmas we ensure - // correct overriding. + // Now see if there are any named pragmas for this declaration. By + // doing this after handling the position pragmas we ensure correct + // overriding. // { - decl_pragmas::const_iterator i (decl_pragmas_.find (t)); + decl_pragmas::const_iterator i (decl_pragmas_.find (decl)); if (i != decl_pragmas_.end ()) prags.insert (i->second.begin (), i->second.end ()); @@ -2045,11 +2141,11 @@ process_pragmas (tree t, } void parser::impl:: -process_named_pragmas (tree t, node& node) +process_named_pragmas (declaration const& decl, node& node) { pragma_set prags; - decl_pragmas::const_iterator i (decl_pragmas_.find (t)); + decl_pragmas::const_iterator i (decl_pragmas_.find (decl)); if (i != decl_pragmas_.end ()) prags.insert (i->second.begin (), i->second.end ()); diff --git a/odb/pragma.cxx b/odb/pragma.cxx index 6fea747..4609c4d 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -22,6 +22,12 @@ using namespace cutl; using container::any; +virt_declarations virt_declarations_; +loc_pragmas loc_pragmas_; +decl_pragmas decl_pragmas_; +ns_loc_pragmas ns_loc_pragmas_; +pragma_name_set simple_value_pragmas_; + template void accumulate (compiler::context& ctx, string const& k, any const& v, location_t) @@ -40,13 +46,6 @@ accumulate (compiler::context& ctx, string const& k, any const& v, location_t) c.push_back (v.value ()); } -// Lists of pragmas. -// -loc_pragmas loc_pragmas_; -decl_pragmas decl_pragmas_; -ns_loc_pragmas ns_loc_pragmas_; -pragma_name_set simple_value_pragmas_; - // Parse a qualified string. It can be in one of the following formats: // // "foo.bar.baz" (can have empty leading component, e.g., ".bar.baz") @@ -317,6 +316,7 @@ resolve_scoped_name (cxx_lexer& l, cpp_ttype& tt, string& tl, tree& tn, + tree start_scope, string& name, bool is_type, string const& prag, @@ -328,7 +328,7 @@ resolve_scoped_name (cxx_lexer& l, cpp_ttype ptt; // Not used. tree r ( lookup::resolve_scoped_name ( - l, tt, tl, tn, ptt, current_scope (), name, is_type, trailing_scope)); + l, tt, tl, tn, ptt, start_scope, name, is_type, trailing_scope)); if (prev_tt != 0) *prev_tt = ptt; @@ -354,18 +354,19 @@ resolve_scoped_name (cxx_lexer& l, } static bool -check_spec_decl_type (tree d, +check_spec_decl_type (declaration const& d, string const& name, string const& p, location_t l) { - int tc (TREE_CODE (d)); + int tc (d.tree_code ()); + bool type (TREE_CODE_CLASS (tc) == tcc_type); if (p == "id") { // Id can be used for both data members and objects. // - if (tc != FIELD_DECL && !CLASS_TYPE_P (d)) + if (tc != FIELD_DECL && tc != RECORD_TYPE) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a data member or class" << endl; @@ -375,7 +376,6 @@ check_spec_decl_type (tree d, else if (p == "auto" || p == "column" || p == "inverse" || - p == "transient" || p == "version" || p == "index" || p == "unique" || @@ -390,12 +390,24 @@ check_spec_decl_type (tree d, return false; } } + else if (p == "transient") + { + // Transient can be used for both data members and classes (object, + // view, or composite value). + // + if (tc != FIELD_DECL && tc != RECORD_TYPE) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a data member or class" << endl; + return false; + } + } else if (p == "readonly") { // Readonly can be used for both data members and classes (object or // composite value). // - if (tc != FIELD_DECL && !CLASS_TYPE_P (d)) + if (tc != FIELD_DECL && tc != RECORD_TYPE) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a data member or class" << endl; @@ -433,7 +445,7 @@ check_spec_decl_type (tree d, // Table can be used for namespaces, members (container), and types // (container, object, or view). // - if (tc != NAMESPACE_DECL && tc != FIELD_DECL && !TYPE_P (d)) + if (tc != NAMESPACE_DECL && tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a namespace, type, or data member" << endl; @@ -444,7 +456,7 @@ check_spec_decl_type (tree d, { // Session can be used only for namespaces and objects. // - if (tc != NAMESPACE_DECL && !CLASS_TYPE_P (d)) + if (tc != NAMESPACE_DECL && tc != RECORD_TYPE) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a namespace or class" << endl; @@ -455,7 +467,7 @@ check_spec_decl_type (tree d, { // For now schema can be used only for namespaces and objects. // - if (tc != NAMESPACE_DECL && !CLASS_TYPE_P (d)) + if (tc != NAMESPACE_DECL && tc != RECORD_TYPE) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a namespace or class" << endl; @@ -470,7 +482,7 @@ check_spec_decl_type (tree d, { // Type can be used for both members and types. // - if (tc != FIELD_DECL && !TYPE_P (d)) + if (tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type or data member" << endl; @@ -481,7 +493,7 @@ check_spec_decl_type (tree d, { // Default can be used for both members and types. // - if (tc != FIELD_DECL && !TYPE_P (d)) + if (tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type or data member" << endl; @@ -496,7 +508,7 @@ check_spec_decl_type (tree d, // Container columns can be used for both members (container) and // types (container). // - if (tc != FIELD_DECL && !TYPE_P (d)) + if (tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type or data member" << endl; @@ -511,7 +523,7 @@ check_spec_decl_type (tree d, { // Options can be used for both members and types. // - if (tc != FIELD_DECL && !TYPE_P (d)) + if (tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type or data member" << endl; @@ -526,7 +538,7 @@ check_spec_decl_type (tree d, // Null pragmas can be used for both members and types (values, // containers, and pointers). // - if (tc != FIELD_DECL && !TYPE_P (d)) + if (tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type or data member" << endl; @@ -538,13 +550,24 @@ check_spec_decl_type (tree d, // Unordered can be used for both members (container) and // types (container). // - if (tc != FIELD_DECL && !TYPE_P (d)) + if (tc != FIELD_DECL && !type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type or data member" << endl; return false; } } + else if (p == "virtual") + { + // Virtual is specified for a member. + // + if (tc != FIELD_DECL) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a data member" << endl; + return false; + } + } else { error (l) << "unknown db pragma " << p << endl; @@ -555,7 +578,7 @@ check_spec_decl_type (tree d, } static void -add_pragma (pragma const& prag, tree decl, bool ns) +add_pragma (pragma const& prag, declaration const& decl, bool ns) { if (decl) decl_pragmas_[decl].insert (prag); @@ -580,7 +603,7 @@ handle_pragma (cxx_lexer& l, string const& p, string const& qualifier, any& qualifier_value, - tree decl, + declaration const& decl, string const& decl_name, bool ns) // True if this is a position namespace pragma. { @@ -860,7 +883,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -876,7 +899,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -918,7 +941,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1010,7 +1033,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1046,7 +1069,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1083,7 +1106,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1181,7 +1204,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1193,7 +1216,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1205,7 +1228,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1217,7 +1240,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; val = l.location (); @@ -1230,7 +1253,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1266,7 +1289,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1330,7 +1353,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1349,7 +1372,8 @@ handle_pragma (cxx_lexer& l, view_object vo; vo.kind = view_object::object; - vo.obj_node = resolve_scoped_name (l, tt, tl, tn, vo.obj_name, true, p); + vo.obj_node = resolve_scoped_name ( + l, tt, tl, tn, current_scope (), vo.obj_name, true, p); if (vo.obj_node == 0) return; // Diagnostics has already been issued. @@ -1415,7 +1439,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1455,7 +1479,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1471,7 +1495,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1611,7 +1635,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1653,7 +1677,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1711,7 +1735,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1751,7 +1775,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1769,7 +1793,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1814,7 +1838,8 @@ handle_pragma (cxx_lexer& l, { // We have a potentially scopped enumerator name. // - dv.node = resolve_scoped_name (l, tt, tl, tn, dv.value, false, p); + dv.node = resolve_scoped_name ( + l, tt, tl, tn, current_scope (), dv.value, false, p); if (dv.node == 0) return; // Diagnostics has already been issued. @@ -1892,7 +1917,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; if (l.next (tl, &tn) != CPP_OPEN_PAREN) @@ -1926,7 +1951,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1938,7 +1963,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1950,7 +1975,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -1962,7 +1987,7 @@ handle_pragma (cxx_lexer& l, // Make sure we've got the correct declaration type. // - if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + if (decl && !check_spec_decl_type (decl, decl_name, p, loc)) return; tt = l.next (tl, &tn); @@ -2017,12 +2042,13 @@ handle_pragma (cxx_lexer& l, // static bool -check_qual_decl_type (tree d, +check_qual_decl_type (declaration const& d, string const& name, string const& p, location_t l) { - int tc (TREE_CODE (d)); + int tc (d.tree_code ()); + bool type (TREE_CODE_CLASS (tc) == tcc_type); if (p == "map") { @@ -2069,7 +2095,7 @@ check_qual_decl_type (tree d, } else if (p == "value") { - if (!TYPE_P (d)) + if (!type) { error (l) << "name '" << name << "' in db pragma " << p << " does " << "not refer to a type" << endl; @@ -2118,7 +2144,8 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) string tl; tree tn; - tree decl (0), orig_decl (0); + declaration decl; + tree orig_decl (0); // Original declarations as used in the pragma. string decl_name; string name (p); // Pragma name. @@ -2141,7 +2168,8 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) ct.loc = loc; val = ct; name = "custom-db-types"; - orig_decl = decl = global_namespace; + orig_decl = global_namespace; + decl = declaration (orig_decl); adder = &accumulate; tt = l.next (tl, &tn); } @@ -2222,7 +2250,8 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) // token type (tt) and token literal (tl) variables should contain // the correct values. // - orig_decl = decl = current_scope (); + orig_decl = current_scope (); + decl = declaration (orig_decl); } else { @@ -2231,7 +2260,7 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) // cxx_tokens_lexer l; l.start (saved_tokens, loc); - handle_pragma (l, "index", "member", val, 0, "", false); + handle_pragma (l, "index", "member", val, declaration (), "", false); return; } } @@ -2255,7 +2284,7 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) { cpp_ttype ptt; orig_decl = resolve_scoped_name ( - l, tt, tl, tn, decl_name, true, p, true, &ptt); + l, tt, tl, tn, current_scope (), decl_name, true, p, true, &ptt); if (orig_decl == 0) return; // Diagnostics has already been issued. @@ -2267,9 +2296,9 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) orig_decl = TREE_TYPE (orig_decl); if (TYPE_P (orig_decl)) // Can be a template. - decl = TYPE_MAIN_VARIANT (orig_decl); + decl = declaration (TYPE_MAIN_VARIANT (orig_decl)); else - decl = orig_decl; + decl = declaration (orig_decl); if (tt == CPP_STRING && ptt != CPP_SCOPE) { @@ -2286,7 +2315,10 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) } } else - orig_decl = decl = current_scope (); + { + orig_decl = current_scope (); + decl = declaration (orig_decl); + } // Make sure we've got the correct declaration type. // @@ -2325,19 +2357,21 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) if (tt == CPP_NAME || tt == CPP_SCOPE) { - decl = resolve_scoped_name (l, tt, tl, tn, decl_name, false, p); + orig_decl = resolve_scoped_name ( + l, tt, tl, tn, current_scope (), decl_name, false, p); - if (decl == 0) + if (orig_decl == 0) return; // Diagnostics has already been issued. // Make sure we've got the correct declaration type. // - if (!check_qual_decl_type (decl, decl_name, p, loc)) + if (!check_qual_decl_type (orig_decl, decl_name, p, loc)) return; // Resolve namespace aliases if any. // - decl = ORIGINAL_NAMESPACE (decl); + orig_decl = ORIGINAL_NAMESPACE (orig_decl); + decl = declaration (orig_decl); if (tt != CPP_CLOSE_PAREN) { @@ -2349,7 +2383,8 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) } else if (tt == CPP_CLOSE_PAREN) { - decl = global_namespace; + orig_decl = global_namespace; + decl = declaration (orig_decl); tt = l.next (tl, &tn); } else @@ -2391,7 +2426,8 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) // if (tt == CPP_NAME || tt == CPP_KEYWORD || tt == CPP_SCOPE) { - orig_decl = resolve_scoped_name (l, tt, tl, tn, decl_name, true, p); + orig_decl = resolve_scoped_name ( + l, tt, tl, tn, current_scope (), decl_name, true, p); if (orig_decl == 0) return; // Diagnostics has already been issued. @@ -2403,9 +2439,9 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) orig_decl = TREE_TYPE (orig_decl); if (TYPE_P (orig_decl)) // Can be a template. - decl = TYPE_MAIN_VARIANT (orig_decl); + decl = declaration (TYPE_MAIN_VARIANT (orig_decl)); else - decl = orig_decl; + decl = declaration (orig_decl); // Make sure we've got the correct declaration type. // @@ -2438,30 +2474,249 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) { tt = l.next (tl, &tn); - if (tt == CPP_NAME || tt == CPP_SCOPE) + if (tt != CPP_NAME && tt != CPP_SCOPE) + { + error (l) << "data member name expected in db pragma " << p << endl; + return; + } + + // We need to see if this is a virtual data member declaration. Also, + // if it is not, then the name can still refer to one so we need to + // take extra steps to handle that. But first, we save the name and + // look for the 'virtual' specifier. + // + cxx_tokens name_tokens; + for (; tt != CPP_CLOSE_PAREN && tt != CPP_EOF; tt = l.next (tl, &tn)) + name_tokens.push_back (cxx_token (l.location (), tt, tl, tn)); + + if (tt != CPP_CLOSE_PAREN) + { + error (l) << "')' expected at the end of db pragma " << p << endl; + return; + } + + // Now scan the remainder of the pragma looking for the 'virtual' + // keyword and saving the tokens in between for later. + // + bool virt (false); + size_t balance (0); + for (tt = l.next (tl, &tn); tt != CPP_EOF; tt = l.next (tl, &tn)) + { + switch (tt) + { + case CPP_OPEN_PAREN: + { + balance++; + break; + } + case CPP_CLOSE_PAREN: + { + if (balance > 0) + balance--; + else + { + error (l) << "unbalanced parenthesis in db pragma " << p << endl; + return; + } + break; + } + default: + { + if (balance == 0 && tt == CPP_KEYWORD && tl == "virtual") + virt = true; + break; + } + } + + if (virt) + break; + + saved_tokens.push_back (cxx_token (l.location (), tt, tl, tn)); + } + + if (balance != 0) { - decl = resolve_scoped_name (l, tt, tl, tn, decl_name, false, p); + error (l) << "unbalanced parenthesis in db pragma " << p << endl; + return; + } - if (decl == 0) + // Regardless of whether this is a virtual member declaration or a + // reference, resolve its scope name (if one is specified), which + // should be a class. We will need it in both cases. + // + tree scope; + if (name_tokens.size () > 2) // scope::name + { + size_t n (name_tokens.size ()); + + if (name_tokens[n - 2].type != CPP_SCOPE || + name_tokens[n - 1].type != CPP_NAME) + { + error (l) << "invalid name in db pragma " << p << endl; + return; + } + + cxx_tokens scope_tokens (1, name_tokens.back ()); + name_tokens.pop_back (); // :: + name_tokens.pop_back (); // name + name_tokens.swap (scope_tokens); + + cxx_tokens_lexer l; + l.start (scope_tokens); + + tree tn; + string tl; + cpp_ttype tt (l.next (tl)); + + scope = resolve_scoped_name ( + l, tt, tl, tn, current_scope (), decl_name, true, p); + + if (scope == 0) return; // Diagnostics has already been issued. - // Make sure we've got the correct declaration type. + scope = TREE_TYPE (scope); + + if (tt != CPP_EOF) + { + error (l) << "invalid name in db pragma " << p << endl; + return; + } + + decl_name += "::"; + } + else + scope = current_scope (); + + if (virt) + { + // Should be a single name. // - if (!check_qual_decl_type (decl, decl_name, p, loc)) + if (name_tokens.size () > 1 || name_tokens.back ().type != CPP_NAME) + { + location_t l (name_tokens.back ().loc); + error (l) << "invalid name in db pragma " << p << endl; return; + } + string const& name (name_tokens.back ().literal); - if (tt != CPP_CLOSE_PAREN) + // Parse the remainder of the virtual specifier. + // + // virtual() + // + tree type; + string type_name; { - error (l) << "')' expected at the end of db pragma " << p << endl; + string p (tl); + location_t loc (l.location ()); + + if (l.next (tl, &tn) != CPP_OPEN_PAREN) + { + error (l) << "'(' expected after db pragma " << p << endl; + return; + } + + tt = l.next (tl, &tn); + + // Can be built-in type (e.g., bool). + // + if (tt == CPP_NAME || tt == CPP_KEYWORD || tt == CPP_SCOPE) + { + type = resolve_scoped_name ( + l, tt, tl, tn, current_scope (), type_name, true, p); + + if (type == 0) + return; // Diagnostics has already been issued. + + if (TREE_CODE (type) != TYPE_DECL) + { + error (loc) << "name '" << type_name << "' in db pragma " + << p << " does not refer to a type" << endl; + return; + } + + type = TREE_TYPE (type); + } + else + { + error (l) << "type name expected in db pragma " << p << endl; + return; + } + + if (tt != CPP_CLOSE_PAREN) + { + error (l) << "')' expected at the end of db pragma " << p << endl; + return; + } + + tt = l.next (tl, &tn); + } + + pair r ( + virt_declarations_[scope].insert ( + virt_declaration (loc, name, FIELD_DECL, type))); + + if (!r.second) + { + error (loc) << "virtual data member declaration '" << name + << "' conflicts with a previous declaration" << endl; + + info (r.first->loc) << "'" << name << "' was previously " + << "declared here" << endl; return; } - tt = l.next (tl, &tn); + decl_name += name; + decl = declaration (*r.first); + + // Mark it as virtual using the standard pragma machinery. + // + add_pragma ( + pragma ("virtual", "virtual", true, loc, &check_spec_decl_type, 0), + decl, + false); } else { - error (l) << "data member name expected in db pragma " << p << endl; - return; + // This is not a virtual member declaration but the name can + // still refer to one. To handle this look for real and virtual + // members in the scope that we just resolved. + // + if (name_tokens.size () == 1 && name_tokens.back ().type == CPP_NAME) + { + virt_declarations::iterator i (virt_declarations_.find (scope)); + + if (i != virt_declarations_.end ()) + { + virt_declaration_set::iterator j ( + i->second.find (name_tokens.back ().literal, FIELD_DECL)); + + if (j != i->second.end ()) + decl = declaration (*j); + } + } + + if (!decl) + { + cxx_tokens_lexer l; + l.start (name_tokens); + + tree tn; + string tl; + cpp_ttype tt (l.next (tl)); + + orig_decl = resolve_scoped_name ( + l, tt, tl, tn, scope, decl_name, false, p); + + if (orig_decl == 0) + return; // Diagnostics has already been issued. + + decl = declaration (orig_decl); + } + + // Make sure we've got the correct declaration type. + // + if (!check_qual_decl_type (decl, decl_name, p, loc)) + return; } } } @@ -2502,7 +2757,7 @@ handle_pragma_qualifier (cxx_lexer& l, string const& p) p == "transient" || p == "version") { - handle_pragma (l, p, "member", val, 0, "", false); + handle_pragma (l, p, "member", val, declaration (), "", false); return; } else @@ -2894,7 +3149,10 @@ post_process_pragmas () for (decl_pragmas::iterator i (decl_pragmas_.begin ()), e (decl_pragmas_.end ()); i != e; ++i) { - tree type (i->first); + if (i->first.virt) + continue; + + tree type (i->first.decl.real); if (!(CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))) continue; diff --git a/odb/pragma.hxx b/odb/pragma.hxx index 8751b39..f656079 100644 --- a/odb/pragma.hxx +++ b/odb/pragma.hxx @@ -15,12 +15,124 @@ #include #include +struct virt_declaration +{ + virt_declaration (location_t l, std::string const& n, int tc, tree t) + : loc (l), name (n), tree_code (tc), type (t) {} + + location_t loc; + std::string name; + int tree_code; + tree type; // Declaration's type. +}; + +// Note that we consider virtual declarations with the same name but +// different tree codes unequal. If that is too loose, then the +// inserting code must do additional checks. +// +struct virt_declaration_comparator +{ + bool + operator () (virt_declaration const& x, virt_declaration const& y) const + { + return x.name < y.name || (x.name == y.name && x.tree_code < y.tree_code); + } +}; + +struct virt_declaration_set: + std::set +{ + typedef std::set base; + + iterator + find (std::string const& name, int tree_code) const + { + return base::find (virt_declaration (0, name, tree_code, 0)); + } +}; + +// Map of scopes (e.g., class, namespace) to sets of virtual declarations. +// +typedef std::map virt_declarations; +extern virt_declarations virt_declarations_; + +// Real or virtual declaration. If it is real, then it is a pointer to +// the GCC tree node. Otherwise, it is a pointer to virt_declaration +// from virt_declarations_ above. +// +struct declaration +{ + declaration (): virt (false) {decl.real = 0;} + declaration (tree d): virt (false) {decl.real = d;} + declaration (virt_declaration const& d): virt (true) {decl.virt = &d;} + + bool virt; + + union + { + tree real; + virt_declaration const* virt; + } decl; + + int + tree_code () const + { + return (virt ? decl.virt->tree_code : TREE_CODE (decl.real)); + } + + typedef bool declaration::*bool_convertible; + operator bool_convertible () const + { + return ptr () == 0 ? 0 : &declaration::virt; + } + +public: + bool + operator== (declaration const& x) const + { + return virt == x.virt && ptr () == x.ptr (); + } + + bool + operator!= (declaration const& x) const + { + return !(*this == x); + } + + bool + operator< (declaration const& x) const + { + return virt < x.virt || (virt == x.virt && ptr () < x.ptr ()); + } + +public: + void const* + ptr () const + { + return virt + ? static_cast (decl.virt) + : static_cast (decl.real); + } +}; + +inline bool +operator== (declaration const& x, tree y) +{ + return !x.virt && x.decl.real == y; +} + +inline bool +operator== (tree x, declaration const& y) +{ + return !y.virt && y.decl.real == x; +} + struct pragma { // Check that the pragma is applicable to the declaration. Return true // on success, complain and return false otherwise. // - typedef bool (*check_func) (tree decl, + typedef bool (*check_func) (declaration const& decl, std::string const& decl_name, std::string const& prag_name, location_t); @@ -120,9 +232,9 @@ struct ns_loc_pragma typedef std::vector ns_loc_pragmas; extern ns_loc_pragmas ns_loc_pragmas_; -// Pragmas associated with specific declarations. +// Pragmas associated with specific declarations (real or virtual). // -typedef std::map decl_pragmas; +typedef std::map decl_pragmas; extern decl_pragmas decl_pragmas_; // List of pragma names (in context name form) that disqualify a value diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx index edafeac..8ab9a1f 100644 --- a/odb/relational/processor.cxx +++ b/odb/relational/processor.cxx @@ -491,6 +491,13 @@ namespace relational void process_access (semantics::data_member& m, std::string const& k) { + bool virt (m.count ("virtual")); + + // Ignore certain special virtual members. + // + if (virt && (m.count ("polymorphic-ref") || m.count ("discriminator"))) + return; + char const* kind (k == "get" ? "accessor" : "modifier"); semantics::class_& c (dynamic_cast (m.scope ())); @@ -503,10 +510,11 @@ namespace relational semantics::access const& a (m.named ().access ()); member_access& ma (m.set (k, member_access (m.location (), true))); - // If this member is public or if we are a friend of this - // class, then go for the member directly. + // If this member is not virtual and is either public or if we + // are a friend of this class, then go for the member directly. // - if (a == semantics::access::public_ || c.get ("friend")) + if (!virt && (a == semantics::access::public_ || + c.get ("friend"))) { ma.expr.push_back (cxx_token (0, CPP_KEYWORD, "this")); ma.expr.push_back (cxx_token (0, CPP_DOT)); @@ -611,15 +619,29 @@ namespace relational { location const& l (m.location ()); - error (l) << "data member '" << m.name () << "' is " << a.string () - << " and no suitable " << kind << " function could be " - << "automatically found" << endl; + if (virt) + { + error (l) << "no suitable " << kind << " function could be " + << "automatically found for virtual data member '" + << m.name () << "'" << endl; + + info (l) << "use '#pragma db " << k << "' to explicitly " + << "specify the " << kind << " function or " + << "expression" << endl; + } + else + { + error (l) << "data member '" << m.name () << "' is " + << a.string () << " and no suitable " << kind + << " function could be automatically found" << endl; - info (l) << "consider making class 'odb::access' a friend of " - << "class '" << class_name (c) << "'" << endl; + info (l) << "consider making class 'odb::access' a friend of " + << "class '" << class_name (c) << "'" << endl; - info (l) << "or use '#pragma db " << k << "' to explicitly " - << "specify the " << kind << " function" << endl; + info (l) << "or use '#pragma db " << k << "' to explicitly " + << "specify the " << kind << " function or " + << "expression" << endl; + } throw operation_failed (); } @@ -1439,37 +1461,45 @@ namespace relational if (m.count ("inverse")) { string name (m.get ("inverse")); - tree decl ( - lookup_qualified_name ( - c->tree_node (), get_identifier (name.c_str ()), false, false)); + location_t loc (m.get ("inverse-location")); - if (decl == error_mark_node || TREE_CODE (decl) != FIELD_DECL) + try { - os << m.file () << ":" << m.line () << ":" << m.column () << ": " - << "error: unable to resolve data member '" << name << "' " - << "specified with '#pragma db inverse' in class '" - << class_fq_name (*c) << "'" << endl; + data_member& im ( + c->lookup (name, class_::include_hidden)); + + // @@ Would be good to check that the other end is actually + // an object pointer, is not marked as transient or inverse, + // and points to the correct object. But the other class may + // not have been processed yet. + // + m.remove ("inverse"); + m.set (kp + (kp.empty () ? "": "-") + "inverse", &im); + } + catch (semantics::unresolved const& e) + { + if (e.type_mismatch) + error (loc) << "name '" << name << "' in '#pragma db " << + "inverse' does not refer to a data member" << endl; + else + error (loc) << "unable to resolve data member '" << name << + "' specified with '#pragma db inverse'" << endl; + throw operation_failed (); } + catch (semantics::ambiguous const& e) + { + error (loc) << "data member name '" << name << "' specified " << + "with '#pragma db inverse' is ambiguous" << endl; - data_member* im (dynamic_cast (unit.find (decl))); + info (e.first.named ().location ()) << "could resolve to this " << + "data member" << endl; + + info (e.second.named ().location ()) << "or could resolve to " << + "this data member" << endl; - if (im == 0) - { - os << m.file () << ":" << m.line () << ":" << m.column () << ": " - << "ice: unable to find semantic graph node corresponding to " - << "data member '" << name << "' in class '" - << class_fq_name (*c) << "'" << endl; throw operation_failed (); } - - // @@ Would be good to check that the other end is actually - // an object pointer, is not marked as inverse, and points - // to the correct object. But the other class may not have - // been processed yet. - // - m.remove ("inverse"); - m.set (kp + (kp.empty () ? "": "-") + "inverse", im); } return c; @@ -1760,6 +1790,9 @@ namespace relational // try { + using semantics::scope; + using semantics::class_; + if (i->kind != column_expr_part::reference) continue; @@ -1769,8 +1802,7 @@ namespace relational tree tn; cpp_ttype tt (lex_.next (tl, &tn)); - string name; - tree decl (0); + data_member* m (0); view_object* vo (0); // Check if this is an alias. @@ -1787,17 +1819,18 @@ namespace relational // if (lex_.next (tl, &tn) != CPP_SCOPE) { - error (i->loc) - << "member name expected after an alias in db pragma " - << "column" << endl; + error (i->loc) << "member name expected after an alias " << + "in db pragma column" << endl; throw operation_failed (); } - tt = lex_.next (tl, &tn); + if (lex_.next (tl, &tn) != CPP_NAME) + throw lookup::invalid_name (); - cpp_ttype ptt; // Not used. - decl = lookup::resolve_scoped_name ( - lex_, tt, tl, tn, ptt, vo->obj->tree_node (), name, false); + m = &vo->obj->lookup ( + tl, scope::include_hidden); + + tt = lex_.next (tl, &tn); } } @@ -1807,45 +1840,36 @@ namespace relational { // Also get the object type. We need to do it so that // we can get the correct (derived) table name (the - // member can come from a base class). + // member itself can come from a base class). // - tree type; + scope* s; + string name; cpp_ttype ptt; // Not used. - decl = lookup::resolve_scoped_name ( - lex_, tt, tl, tn, ptt, i->scope, name, false, false, &type); - - type = TYPE_MAIN_VARIANT (type); + m = &lookup::resolve_scoped_name ( + lex_, tt, tl, tn, ptt, + dynamic_cast (*unit.find (i->scope)), + name, + false, + &s); - view_object_map::iterator j (omap_.find (type)); + view_object_map::iterator j ( + omap_.find (dynamic_cast (s))); if (j == omap_.end ()) { - error (i->loc) - << "name '" << name << "' in db pragma column does not " - << "refer to a data member of a persistent class that " - << "is used in this view" << endl; + error (i->loc) << "name '" << name << "' in db pragma " << + "column does not refer to a data member of a " << + "persistent class that is used in this view" << endl; throw operation_failed (); } vo = j->second; } - // Check that we have a data member. - // - if (TREE_CODE (decl) != FIELD_DECL) - { - error (i->loc) << "name '" << name << "' in db pragma column " - << "does not refer to a data member" << endl; - throw operation_failed (); - } - - data_member* m (dynamic_cast (unit.find (decl))); i->member_path.push_back (m); // Figure out the table name/alias for this member. // - using semantics::class_; - if (class_* root = polymorphic (*vo->obj)) { // If the object is polymorphic, then figure out which of the @@ -1882,19 +1906,18 @@ namespace relational { lex_.next (tl, &tn); // Get CPP_NAME. - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - - decl = lookup_qualified_name ( - type, get_identifier (tl.c_str ()), false, false); - - if (decl == error_mark_node || TREE_CODE (decl) != FIELD_DECL) + // Check that the outer member is composite and also + // unwrap it while at it. + // + class_* comp (composite_wrapper (utype (*m))); + if (comp == 0) { - error (i->loc) << "name '" << tl << "' in db pragma column " - << "does not refer to a data member" << endl; + error (i->loc) << "data member '" << m->name () << "' " << + "specified in db pragma column is not composite" << endl; throw operation_failed (); } - m = dynamic_cast (unit.find (decl)); + m = &comp->lookup (tl, class_::include_hidden); i->member_path.push_back (m); } @@ -1909,10 +1932,28 @@ namespace relational error (i->loc) << "invalid name in db pragma column" << endl; throw operation_failed (); } - catch (lookup::unable_to_resolve const& e) + catch (semantics::unresolved const& e) + { + if (e.type_mismatch) + error (i->loc) << "name '" << e.name << "' in db pragma " << + "column does not refer to a data member" << endl; + else + error (i->loc) << "unable to resolve data member '" << + e.name << "' specified with db pragma column" << endl; + + throw operation_failed (); + } + catch (semantics::ambiguous const& e) { - error (i->loc) << "unable to resolve name '" << e.name () - << "' in db pragma column" << endl; + error (i->loc) << "data member name '" << e.first.name () << + "' specified with db pragma column is ambiguous" << endl; + + info (e.first.named ().location ()) << "could resolve to " << + "this data member" << endl; + + info (e.second.named ().location ()) << "or could resolve " << + "to this data member" << endl; + throw operation_failed (); } } @@ -2395,7 +2436,8 @@ namespace relational size_t l (idm.line ()), col (idm.column ()); semantics::data_member& m ( - unit.new_node (f, l, col)); + unit.new_node (f, l, col, tree (0))); + m.set ("virtual", true); // Make it the first member in the class. // @@ -2441,10 +2483,12 @@ namespace relational // location_t loc (c.get ("polymorphic-location")); semantics::data_member& m ( - unit.new_node ( + unit.new_node ( path (LOCATION_FILE (loc)), LOCATION_LINE (loc), - LOCATION_COLUMN (loc))); + LOCATION_COLUMN (loc), + tree (0))); + m.set ("virtual", true); // Insert it after the id member (or first if this id comes // from reuse-base). @@ -2488,7 +2532,6 @@ namespace relational // First resolve member names. // string tl; - tree tn; cpp_ttype tt; index::members_type::iterator j (in.members.begin ()); @@ -2501,75 +2544,79 @@ namespace relational try { - lex_.start (im.name); - tt = lex_.next (tl, &tn); + using semantics::data_member; // The name was already verified to be syntactically correct so - // we don't need to do any error checking. - // - string name; // Not used. - cpp_ttype ptt; // Not used. - tree decl ( - lookup::resolve_scoped_name ( - lex_, tt, tl, tn, ptt, c.tree_node (), name, false)); - - // Check that we have a data member. + // we don't need to do any extra error checking in this area. // - if (TREE_CODE (decl) != FIELD_DECL) - { - error (im.loc) << "name '" << tl << "' in db pragma member " - << "does not refer to a data member" << endl; - throw operation_failed (); - } + lex_.start (im.name); + tt = lex_.next (tl); - using semantics::data_member; + data_member& m ( + c.lookup (tl, type::include_hidden)); - data_member* m (dynamic_cast (unit.find (decl))); - im.path.push_back (m); + im.path.push_back (&m); + tt = lex_.next (tl); - if (container (*m)) + if (container (m)) break; // Resolve nested members if any. // - for (; tt == CPP_DOT; tt = lex_.next (tl, &tn)) + for (; tt == CPP_DOT; tt = lex_.next (tl)) { - lex_.next (tl, &tn); // Get CPP_NAME. + lex_.next (tl); // Get CPP_NAME. - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); + data_member& om (*im.path.back ()); - decl = lookup_qualified_name ( - type, get_identifier (tl.c_str ()), false, false); - - if (decl == error_mark_node || TREE_CODE (decl) != FIELD_DECL) + // Check that the outer member is composite and also + // unwrap it while at it. + // + semantics::class_* comp (composite_wrapper (utype (om))); + if (comp == 0) { - error (im.loc) << "name '" << tl << "' in db pragma member " - << "does not refer to a data member" << endl; + error (im.loc) << "data member '" << om.name () << "' " << + "specified in db pragma member is not composite" << endl; throw operation_failed (); } - m = dynamic_cast (unit.find (decl)); - im.path.push_back (m); + data_member& nm ( + comp->lookup (tl, type::include_hidden)); - if (container (*m)) + im.path.push_back (&nm); + + if (container (nm)) { - tt = lex_.next (tl, &tn); // Get CPP_DOT. + tt = lex_.next (tl); // Get CPP_DOT. break; // Only breaks out of the inner loop. } } - if (container (*m)) + if (container (*im.path.back ())) break; } - catch (lookup::invalid_name const&) + catch (semantics::unresolved const& e) { - error (im.loc) << "invalid name in db pragma member" << endl; + if (e.type_mismatch) + error (im.loc) << "name '" << e.name << "' in db pragma " << + "member does not refer to a data member" << endl; + else + error (im.loc) << "unable to resolve data member '" << + e.name << "' specified with db pragma member" << endl; + throw operation_failed (); } - catch (lookup::unable_to_resolve const& e) + catch (semantics::ambiguous const& e) { - error (im.loc) << "unable to resolve name '" << e.name () - << "' in db pragma member" << endl; + error (im.loc) << "data member name '" << e.first.name () << + "' specified with db pragma member is ambiguous" << endl; + + info (e.first.named ().location ()) << "could resolve to " << + "this data member" << endl; + + info (e.second.named ().location ()) << "or could resolve " << + "to this data member" << endl; + throw operation_failed (); } } @@ -2587,7 +2634,7 @@ namespace relational throw operation_failed (); } - if (tt != CPP_DOT || lex_.next (tl, &tn) != CPP_NAME || + if (tt != CPP_DOT || lex_.next (tl) != CPP_NAME || (tl != "id" && tl != "index")) { error (j->loc) << ".id or .index special member expected in a " @@ -2597,7 +2644,7 @@ namespace relational string n (tl); - if (lex_.next (tl, &tn) != CPP_EOF) + if (lex_.next (tl) != CPP_EOF) { error (j->loc) << "unexpected text after ." << n << " in " << "db pragma member" << endl; @@ -2786,18 +2833,15 @@ namespace relational if (i->alias.empty ()) { - if (!omap.insert (view_object_map::value_type (n, &*i)).second) + if (!omap.insert (view_object_map::value_type (&o, &*i)).second) { - error (i->loc) - << "persistent class '" << i->obj_name << "' is used in " - << "the view more than once" << endl; + error (i->loc) << "persistent class '" << i->obj_name << + "' is used in the view more than once" << endl; - error (omap[n]->loc) - << "previously used here" << endl; + error (omap[&o]->loc) << "previously used here" << endl; - info (i->loc) - << "use the alias clause to assign it a different name" - << endl; + info (i->loc) << "use the alias clause to assign it a " << + "different name" << endl; throw operation_failed (); } @@ -2811,19 +2855,16 @@ namespace relational for (class_* b (&polymorphic_base (o));; b = &polymorphic_base (*b)) { - view_object_map::value_type v (b->tree_node (), &*i); - if (!omap.insert (v).second) + if (!omap.insert ( + view_object_map::value_type (b, &*i)).second) { - error (i->loc) - << "base class '" << class_name (*b) << "' is " - << "used in the view more than once" << endl; + error (i->loc) << "base class '" << class_name (*b) << + "' is used in the view more than once" << endl; - error (omap[v.first]->loc) - << "previously used here" << endl; + error (omap[b]->loc) << "previously used here" << endl; - info (i->loc) - << "use the alias clause to assign it a different name" - << endl; + info (i->loc) << "use the alias clause to assign it a " << + "different name" << endl; throw operation_failed (); } diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx index 1289b9d..5a02703 100644 --- a/odb/relational/source.cxx +++ b/odb/relational/source.cxx @@ -2760,11 +2760,16 @@ traverse_view (type& c) os << strlit (vq.literal); } else + { + semantics::scope& scope ( + dynamic_cast (*unit.find (vq.scope))); + // Output the pragma location for easier error tracking. // os << "// From " << location_string (vq.loc, true) << endl << translate_expression ( - c, vq.expr, vq.scope, vq.loc, "query", &ph).value; + c, vq.expr, scope, vq.loc, "query", &ph).value; + } os << ");"; @@ -2834,9 +2839,12 @@ traverse_view (type& c) if (!i->alias.empty ()) l += (need_alias_as ? " AS " : " ") + quote_id (i->alias); + semantics::scope& scope ( + dynamic_cast (*unit.find (i->scope))); + expression e ( translate_expression ( - c, i->cond, i->scope, i->loc, "table")); + c, i->cond, scope, i->loc, "table")); if (e.kind != expression::literal) { @@ -2897,9 +2905,12 @@ traverse_view (type& c) continue; } + semantics::scope& scope ( + dynamic_cast (*unit.find (i->scope))); + expression e ( translate_expression ( - c, i->cond, i->scope, i->loc, "object")); + c, i->cond, scope, i->loc, "object")); // Literal expression. // @@ -3343,11 +3354,14 @@ traverse_view (type& c) } else { + semantics::scope& scope ( + dynamic_cast (*unit.find (vq.scope))); + // Output the pragma location for easier error tracking. // os << "// From " << location_string (vq.loc, true) << endl << translate_expression ( - c, vq.expr, vq.scope, vq.loc, "query", &ph).value; + c, vq.expr, scope, vq.loc, "query", &ph).value; os << ");"; @@ -3494,22 +3508,22 @@ namespace relational string& tl, tree& tn, cpp_ttype& ptt, - tree scope, + semantics::scope& start_scope, location_t loc, string const& prag, bool check_ptr, view_alias_map const& amap, view_object_map const& omap) { + using semantics::scope; using semantics::data_member; typedef class_::expression expression; bool multi_obj ((amap.size () + omap.size ()) > 1); - string r ("query_columns"); - string name; - bool fail (false); + string name; + string r ("query_columns"); context& ctx (context::current ()); // This code is quite similar to view_data_members in the type @@ -3517,7 +3531,7 @@ namespace relational // try { - tree decl (0); + data_member* m (0); view_object* vo (0); // Check if this is an alias. @@ -3544,17 +3558,18 @@ namespace relational if (tt != CPP_SCOPE) { - error (loc) - << "member name expected after an alias in db pragma " - << prag << endl; + error (loc) << "member name expected after an alias in db " << + "pragma " << prag << endl; throw operation_failed (); } ptt = tt; - tt = l.next (tl, &tn); + if (l.next (tl, &tn) != CPP_NAME) + throw lookup::invalid_name (); + + m = &vo->obj->lookup (tl, scope::include_hidden); - decl = lookup::resolve_scoped_name ( - l, tt, tl, tn, ptt, vo->obj->tree_node (), name, false); + tt = l.next (tl, &tn); } } @@ -3564,15 +3579,19 @@ namespace relational { // Also get the object type. We need to do it so that // we can get the correct (derived) object name (the - // member can come from a base class). + // member itself can come from a base class). // - tree type; - decl = lookup::resolve_scoped_name ( - l, tt, tl, tn, ptt, scope, name, false, false, &type); - - type = TYPE_MAIN_VARIANT (type); - - view_object_map::const_iterator i (omap.find (type)); + scope* s; + cpp_ttype ptt; // Not used. + m = &lookup::resolve_scoped_name ( + l, tt, tl, tn, ptt, + start_scope, + name, + false, + &s); + + view_object_map::const_iterator i ( + omap.find (dynamic_cast (s))); if (i == omap.end ()) { @@ -3592,26 +3611,7 @@ namespace relational } } - // Check that we have a data member. - // - if (TREE_CODE (decl) != FIELD_DECL) - { - if (fail) - { - error (loc) - << "name '" << name << "' in db pragma " << prag << " " - << "does not refer to a data member" << endl; - throw operation_failed (); - } - else - return expression ( - name + translate_name_trailer (l, tt, tl, tn, ptt)); - } - expression e (vo); - - data_member* m (dynamic_cast (ctx.unit.find (decl))); - r += "::"; r += ctx.public_name (*m); @@ -3633,7 +3633,9 @@ namespace relational // is_null()/is_not_null() will be valid for composite values // as well. // - if (!context::composite_wrapper (context::utype (*m))) + semantics::class_* comp ( + context::composite_wrapper (context::utype (*m))); + if (comp == 0) break; ptt = tt; @@ -3641,25 +3643,12 @@ namespace relational if (tt != CPP_NAME) { - error (loc) - << "name expected after '.' in db pragma " << prag << endl; - throw operation_failed (); - } - - tree type (TYPE_MAIN_VARIANT (TREE_TYPE (decl))); - - decl = lookup_qualified_name ( - type, get_identifier (tl.c_str ()), false, false); - - if (decl == error_mark_node || TREE_CODE (decl) != FIELD_DECL) - { - error (loc) - << "name '" << tl << "' in db pragma " << prag << " does not " - << "refer to a data member" << endl; + error (loc) << "name expected after '.' in db pragma " << + prag << endl; throw operation_failed (); } - m = dynamic_cast (ctx.unit.find (decl)); + m = &comp->lookup (tl, scope::include_hidden); r += '.'; r += ctx.public_name (*m); @@ -3697,33 +3686,47 @@ namespace relational } catch (lookup::invalid_name const&) { - if (fail) - { - error (loc) << "invalid name in db pragma " << prag << endl; - throw operation_failed (); - } - else + if (!fail) return expression ( name + translate_name_trailer (l, tt, tl, tn, ptt)); + + error (loc) << "invalid name in db pragma " << prag << endl; + throw operation_failed (); } - catch (lookup::unable_to_resolve const& e) + catch (semantics::unresolved const& e) { - if (fail) - { - error (loc) << "unable to resolve name '" << e.name () - << "' in db pragma " << prag << endl; - throw operation_failed (); - } - else + if (!fail) return expression ( name + translate_name_trailer (l, tt, tl, tn, ptt)); + + if (e.type_mismatch) + error (loc) << "name '" << e.name << "' in db pragma " << prag << + " does not refer to a data member" << endl; + else + error (loc) << "unable to resolve data member '" << e.name << + "' specified with db pragma " << prag << endl; + + throw operation_failed (); + } + catch (semantics::ambiguous const& e) + { + error (loc) << "data member name '" << e.first.name () << "' " << + "specified with db pragma " << prag << " is ambiguous" << endl; + + info (e.first.named ().location ()) << "could resolve to this " << + "data member" << endl; + + info (e.second.named ().location ()) << "or could resolve to this " << + "data member" << endl; + + throw operation_failed (); } } class_::expression class_:: translate_expression (type& c, cxx_tokens const& ts, - tree scope, + semantics::scope& scope, location_t loc, string const& prag, bool* placeholder) diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx index 21ab776..3ad463b 100644 --- a/odb/relational/source.hxx +++ b/odb/relational/source.hxx @@ -3447,7 +3447,7 @@ namespace relational expression translate_expression (type& c, cxx_tokens const&, - tree scope, + semantics::scope& start_scope, location_t loc, string const& prag, bool* placeholder = 0); 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_; }; } diff --git a/odb/traversal/elements.cxx b/odb/traversal/elements.cxx index 7ba207d..34955d9 100644 --- a/odb/traversal/elements.cxx +++ b/odb/traversal/elements.cxx @@ -75,24 +75,4 @@ namespace traversal { d.dispatch (m.belongs ()); } - - // virtual_data_member - // - void virtual_data_member:: - traverse (type& m) - { - belongs (m); - } - - void virtual_data_member:: - belongs (type& m) - { - belongs (m, *this); - } - - void virtual_data_member:: - belongs (type& m, edge_dispatcher& d) - { - d.dispatch (m.belongs ()); - } } diff --git a/odb/traversal/elements.hxx b/odb/traversal/elements.hxx index c8ea80a..3b90b58 100644 --- a/odb/traversal/elements.hxx +++ b/odb/traversal/elements.hxx @@ -233,20 +233,6 @@ namespace traversal // // - struct virtual_data_member: node - { - virtual void - traverse (type&); - - virtual void - belongs (type&); - - virtual void - belongs (type&, edge_dispatcher&); - }; - - // - // struct unsupported_type: node {}; } diff --git a/odb/validator.cxx b/odb/validator.cxx index 0f67100..55f7edf 100644 --- a/odb/validator.cxx +++ b/odb/validator.cxx @@ -54,8 +54,23 @@ namespace virtual void traverse (type& m) { - if (transient (m)) - return; + semantics::class_& c (dynamic_cast (m.scope ())); + + // If the class is marked transient, then mark each non-virtual + // data member as transient. + // + { + bool t (transient (m)); + + if (!t && c.count ("transient") && !m.count ("virtual")) + { + m.set ("transient", true); + t = true; + } + + if (t) + return; + } count_++; semantics::names* hint; @@ -369,6 +384,19 @@ namespace } } + // Check members. + // + member_.count_ = 0; + names (c); + + if (member_.count_ == 0 && !base) + { + os << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no persistent data members in the class" << endl; + + valid_ = false; + } + // Check special members. // semantics::data_member* id (0); @@ -543,19 +571,6 @@ namespace if (poly_root != 0) c.set ("polymorphic-root", poly_root); - // Check members. - // - member_.count_ = 0; - names (c); - - if (member_.count_ == 0 && !base) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - - valid_ = false; - } - // Update features set based on this object. // if (class_file (c) == unit.file ()) @@ -647,6 +662,19 @@ namespace } } + // Check members. + // + member_.count_ = 0; + names (c); + + if (member_.count_ == 0) + { + os << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no persistent data members in the class" << endl; + + valid_ = false; + } + // Check id. // semantics::data_member* id (0); @@ -676,19 +704,6 @@ namespace valid_ = false; } - // Check members. - // - member_.count_ = 0; - names (c); - - if (member_.count_ == 0) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - - valid_ = false; - } - // Update features set based on this view. // if (class_file (c) == unit.file ()) @@ -732,6 +747,19 @@ namespace } } + // Check members. + // + member_.count_ = 0; + names (c); + + if (member_.count_ == 0 && !base) + { + os << c.file () << ":" << c.line () << ":" << c.column () << ":" + << " error: no persistent data members in the class" << endl; + + valid_ = false; + } + // Check id. // semantics::data_member* id (0); @@ -760,19 +788,6 @@ namespace valid_ = false; } - - // Check members. - // - member_.count_ = 0; - names (c); - - if (member_.count_ == 0 && !base) - { - os << c.file () << ":" << c.line () << ":" << c.column () << ":" - << " error: no persistent data members in the class" << endl; - - valid_ = false; - } } bool& valid_; -- cgit v1.1