From e4b1b83a5a0fd902824071d5db04d7cda17e2f88 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 16 Jun 2015 12:06:18 +0200 Subject: Implement before/after pragmas for virtual data member ordering --- odb/parser.cxx | 40 +++++++++--- odb/pragma.cxx | 193 +++++++++++++++++++++++++++++++++++++++++++++++---------- odb/pragma.hxx | 6 +- 3 files changed, 195 insertions(+), 44 deletions(-) diff --git a/odb/parser.cxx b/odb/parser.cxx index a8e6a6a..ff9f6d0 100644 --- a/odb/parser.cxx +++ b/odb/parser.cxx @@ -188,17 +188,39 @@ private: bool parser::impl::tree_decl:: operator< (tree_decl const& y) const { - location_t xloc ( - decl != 0 - ? real_source_location (decl) - : (vdecl != 0 ? vdecl->loc : prag->loc)); + location_t xl, yl; + int xb (0), yb (0); - location_t yloc ( - y.decl != 0 - ? real_source_location (y.decl) - : (y.vdecl != 0 ? y.vdecl->loc : y.prag->loc)); + if (decl != 0) + xl = real_source_location (decl); + else if (vdecl != 0) + { + xl = vdecl->ord; + xb = vdecl->ord_bias; + } + else + xl = prag->loc; + + if (y.decl != 0) + yl = real_source_location (y.decl); + else if (y.vdecl != 0) + { + yl = y.vdecl->ord; + yb = y.vdecl->ord_bias; + } + else + yl = y.prag->loc; + + // If both are virtual and at the same location, use the definition + // location to order them. + // + if (vdecl != 0 && y.vdecl != 0 && xl == yl && xb == yb) + { + xl = vdecl->loc; + yl = y.vdecl->loc; + } - return xloc < yloc; + return xl < yl || (xl == yl && xb < yb); } // diff --git a/odb/pragma.cxx b/odb/pragma.cxx index b92930a..2994aa1 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -294,7 +294,6 @@ parse_expression (cxx_lexer& l, return true; } - static string parse_scoped_name (cxx_lexer& l, cpp_ttype& tt, @@ -355,6 +354,56 @@ resolve_scoped_name (cxx_lexer& l, } } +// Resolve a data member in the specified scope taking into account virtual +// member declarations. +// +declaration +resolve_data_member (tree scope, + const cxx_tokens& name, + string& decl_name, // Note: appended to. + string const& prag) +{ + declaration decl; + + if (name.size () == 1 && name.back ().type == CPP_NAME) + { + virt_declarations::iterator i (virt_declarations_.find (scope)); + + if (i != virt_declarations_.end ()) + { + string const& n (name.back ().literal); + + virt_declaration_set::const_iterator j (i->second.find (n, FIELD_DECL)); + + if (j != i->second.end ()) + { + decl = declaration (*j); + decl_name += n; + } + } + } + + if (!decl) + { + cxx_tokens_lexer l; + l.start (name); + + tree tn; + string tl; + cpp_ttype tt (l.next (tl)); + + tree d (resolve_scoped_name ( + l, tt, tl, tn, scope, decl_name, false, prag)); + + if (d == 0) + return decl; // Diagnostics has already been issued. + + decl = declaration (d); + } + + return decl; +} + static bool check_spec_decl_type (declaration const& d, string const& name, @@ -2629,6 +2678,13 @@ handle_pragma (cxx_lexer& l, error (l) << "virtual member declaration requires name" << endl; return; } + else if (p == "before" || p == "after") + { + // Stray before/after specifier (i.e., without preceding virtual). + // + error (l) << p << " specifier must follow virtual" << endl; + return; + } else { error (l) << "unknown db pragma " << p << endl; @@ -3371,6 +3427,8 @@ handle_pragma_qualifier (cxx_lexer& l, string p) // tree type; string type_name; + location_t ord (loc); + int ord_bias (0); { string p (tl); location_t loc (l.location ()); @@ -3415,11 +3473,107 @@ handle_pragma_qualifier (cxx_lexer& l, string p) } tt = l.next (tl, &tn); + + // See if we have before/after specifiers. + // + if (tt == CPP_NAME && tl == "before") + { + // before[()] + // + // Before without the member name means first. + // + tt = l.next (tl, &tn); + + if (tt == CPP_OPEN_PAREN) + { + if (l.next (tl, &tn) != CPP_NAME) + { + error (l) << "')' member name expected in db pragma before" + << endl; + } + + string dn; + cxx_tokens ts (1, cxx_token (l.location (), CPP_NAME, tl)); + declaration d (resolve_data_member (scope, ts, dn, "before")); + + if (!d) + return; // Diagnostics has already been issued. + + if (d.virt) + { + ord = d.decl.virt->ord; + ord_bias = d.decl.virt->ord_bias - 1; + } + else + { + ord = real_source_location (d.decl.real); + ord_bias = -1; + } + + if (l.next (tl, &tn) != CPP_CLOSE_PAREN) + { + error (l) << "')' expected at the end of db pragma before" + << endl; + return; + } + + tt = l.next (tl, &tn); + } + else + ord = 0; + } + + if (tt == CPP_NAME && tl == "after") + { + // after[()] + // + // Before without the member name means last. + // + tt = l.next (tl, &tn); + + if (tt == CPP_OPEN_PAREN) + { + if (l.next (tl, &tn) != CPP_NAME) + { + error (l) << "')' member name expected in db pragma after" + << endl; + } + + string dn; + cxx_tokens ts (1, cxx_token (l.location (), CPP_NAME, tl)); + declaration d (resolve_data_member (scope, ts, dn, "after")); + + if (!d) + return; // Diagnostics has already been issued. + + if (d.virt) + { + ord = d.decl.virt->ord; + ord_bias = d.decl.virt->ord_bias + 1; + } + else + { + ord = real_source_location (d.decl.real); + ord_bias = 1; + } + + if (l.next (tl, &tn) != CPP_CLOSE_PAREN) + { + error (l) << "')' expected at the end of db pragma after" + << endl; + return; + } + + tt = l.next (tl, &tn); + } + else + ord = ~location_t (0); + } } pair r ( virt_declarations_[scope].insert ( - virt_declaration (loc, name, FIELD_DECL, type))); + virt_declaration (loc, ord, ord_bias, name, FIELD_DECL, type))); if (!r.second) { @@ -3443,41 +3597,12 @@ handle_pragma_qualifier (cxx_lexer& l, string p) } else { - // 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. + // Not a virtual member declaration. // - 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::const_iterator j ( - i->second.find (name_tokens.back ().literal, FIELD_DECL)); - - if (j != i->second.end ()) - decl = declaration (*j); - } - } + decl = resolve_data_member (scope, name_tokens, decl_name, p); 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); - } + return; // Diagnostics has already been issued. // Make sure we've got the correct declaration type. // diff --git a/odb/pragma.hxx b/odb/pragma.hxx index bde438f..d6b0f42 100644 --- a/odb/pragma.hxx +++ b/odb/pragma.hxx @@ -21,12 +21,16 @@ struct virt_declaration { virt_declaration (location_t l, + location_t o, + int ob, std::string const& n, gcc_tree_code_type tc, tree t) - : loc (l), name (n), tree_code (tc), type (t) {} + : loc (l), ord (o), ord_bias (ob), name (n), tree_code (tc), type (t) {} location_t loc; + location_t ord; // Ordering location for before/after support. + int ord_bias; // Ordering bias for the same locations. std::string name; gcc_tree_code_type tree_code; tree type; // Declaration's type. -- cgit v1.1