aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-08-31 10:03:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-08-31 10:03:45 +0200
commitc0957cfe1c73ecb6c96314e45e7d29b4199b20d6 (patch)
tree96a747f7196baa335cf83ff160527bb8333ca9e3
parented52acc5e65dd9ea2fb2d9c851c2faa61d5cb2d9 (diff)
Add support for virtual data members
New test: common/virtual.
-rw-r--r--odb/context.hxx2
-rw-r--r--odb/lookup.cxx249
-rw-r--r--odb/lookup.hxx37
-rw-r--r--odb/parser.cxx152
-rw-r--r--odb/pragma.cxx424
-rw-r--r--odb/pragma.hxx118
-rw-r--r--odb/relational/processor.cxx325
-rw-r--r--odb/relational/source.cxx151
-rw-r--r--odb/relational/source.hxx2
-rw-r--r--odb/semantics/class.cxx71
-rw-r--r--odb/semantics/class.hxx13
-rw-r--r--odb/semantics/elements.cxx84
-rw-r--r--odb/semantics/elements.hxx59
-rw-r--r--odb/semantics/fundamental.hxx10
-rw-r--r--odb/semantics/namespace.cxx70
-rw-r--r--odb/semantics/namespace.hxx24
-rw-r--r--odb/traversal/elements.cxx20
-rw-r--r--odb/traversal/elements.hxx14
-rw-r--r--odb/validator.cxx97
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_object> view_objects;
// The view_alias_map does not contain entries for tables.
//
typedef std::map<std::string, view_object*> view_alias_map;
-typedef std::map<tree, view_object*> view_object_map;
+typedef std::map<semantics::class_*, view_object*> 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 <odb/lookup.hxx>
+#include <odb/semantics.hxx>
using namespace std;
namespace lookup
{
- std::string
+ // Return canonical fundamental type name (<length> <sign> <type>, 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<semantics::fund_type> (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<semantics::scope&> (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 <string>
#include <odb/cxx-lexer.hxx>
+#include <odb/semantics/elements.hxx>
namespace lookup
{
@@ -45,6 +46,9 @@ namespace lookup
// In this case token will be <something-other-than-name> 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 <typename T>
+ 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<T&> (
+ 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<data_member> (file, line, clmn, tree (0)));
+
+ unit_->new_edge<names> (*c_node, member_node, vd.name, a);
+ belongs& edge (unit_->new_edge<belongs> (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<fund_bool> (boolean_type_node);
define_fund<fund_char> (char_type_node);
define_fund<fund_wchar> (wchar_type_node);
+
+ if (ops_.std () == cxx_version::cxx11)
+ {
+ define_fund<fund_char16> (char16_type_node);
+ define_fund<fund_char32> (char32_type_node);
+ }
+
define_fund<fund_signed_char> (signed_char_type_node);
define_fund<fund_unsigned_char> (unsigned_char_type_node);
define_fund<fund_short> (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 <typename X>
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<X> ());
}
-// 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<custom_db_type>;
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(<fq-name>)
+ //
+ 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<virt_declaration_set::iterator, bool> 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 <cutl/container/any.hxx>
#include <cutl/compiler/context.hxx>
+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<virt_declaration, virt_declaration_comparator>
+{
+ typedef std::set<virt_declaration, virt_declaration_comparator> 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<tree, virt_declaration_set> 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<void const*> (decl.virt)
+ : static_cast<void const*> (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_pragma> 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<tree, pragma_set> decl_pragmas;
+typedef std::map<declaration, pragma_set> 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<semantics::class_&> (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<bool> ("friend"))
+ if (!virt && (a == semantics::access::public_ ||
+ c.get<bool> ("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<string> ("inverse"));
- tree decl (
- lookup_qualified_name (
- c->tree_node (), get_identifier (name.c_str ()), false, false));
+ location_t loc (m.get<location_t> ("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<data_member> (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<data_member*> (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<data_member> (
+ 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<data_member> (
+ lex_, tt, tl, tn, ptt,
+ dynamic_cast<scope&> (*unit.find (i->scope)),
+ name,
+ false,
+ &s);
- view_object_map::iterator j (omap_.find (type));
+ view_object_map::iterator j (
+ omap_.find (dynamic_cast<class_*> (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<data_member*> (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<data_member*> (unit.find (decl));
+ m = &comp->lookup<data_member> (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<virtual_data_member> (f, l, col));
+ unit.new_node<semantics::data_member> (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<location_t> ("polymorphic-location"));
semantics::data_member& m (
- unit.new_node<virtual_data_member> (
+ unit.new_node<semantics::data_member> (
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<data_member> (tl, type::include_hidden));
- data_member* m (dynamic_cast<data_member*> (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<data_member*> (unit.find (decl));
- im.path.push_back (m);
+ data_member& nm (
+ comp->lookup<data_member> (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<semantics::scope&> (*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<semantics::scope&> (*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<semantics::scope&> (*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<semantics::scope&> (*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<data_member> (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<data_member> (
+ l, tt, tl, tn, ptt,
+ start_scope,
+ name,
+ false,
+ &s);
+
+ view_object_map::const_iterator i (
+ omap.find (dynamic_cast<semantics::class_*> (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<data_member*> (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<data_member*> (ctx.unit.find (decl));
+ m = &comp->lookup<data_member> (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 <odb/cxx-lexer.hxx>
#include <odb/semantics/elements.hxx>
+#include <odb/semantics/namespace.hxx>
#include <odb/semantics/unit.hxx>
+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<namespace_> () &&
+ i->named ().is_a<namespace_> ()))
+ 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 <cutl/fs/path.hxx>
#include <cutl/container/graph.hxx>
#include <cutl/container/pointer-iterator.hxx>
+#include <cutl/compiler/type-id.hxx>
#include <cutl/compiler/context.hxx>
#include <odb/gcc-fwd.hxx>
@@ -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 <typename T>
+ 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<T&> (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 ("<fundamental>"), 0, 0, tn) {}
};
+ struct fund_char16: fund_type
+ {
+ fund_char16 (tree tn): node (path ("<fundamental>"), 0, 0, tn) {}
+ };
+
+ struct fund_char32: fund_type
+ {
+ fund_char32 (tree tn): node (path ("<fundamental>"), 0, 0, tn) {}
+ };
+
struct fund_signed_char: fund_type
{
fund_signed_char (tree tn): node (path ("<fundamental>"), 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<namespace_> () &&
+ er->named ().is_a<namespace_> ()))
+ 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 <vector>
+
#include <odb/semantics/elements.hxx>
namespace semantics
{
class namespace_: public scope
{
+ typedef std::vector<namespace_*> 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<semantics::data_member>
- {
- virtual void
- traverse (type&);
-
- virtual void
- belongs (type&);
-
- virtual void
- belongs (type&, edge_dispatcher&);
- };
-
- //
- //
struct unsupported_type: node<semantics::unsupported_type> {};
}
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<semantics::class_&> (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_;