aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/parser.cxx40
-rw-r--r--odb/pragma.cxx193
-rw-r--r--odb/pragma.hxx6
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[(<member>)]
+ //
+ // 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[(<member>)]
+ //
+ // 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<virt_declaration_set::const_iterator, bool> 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.