summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-03-25 13:47:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-03-25 13:47:43 +0200
commit01f77f6d38283b4efbe2b55fc9c7c837fd6498dc (patch)
tree12059fa0c514a3f2b9da2a9419593e3596cc6f5d
parentad637abaa62a26461b276769c35dd1b67036b54b (diff)
Add support for union, enum, class/union template
-rw-r--r--odb/makefile17
-rw-r--r--odb/plugin.cxx718
-rw-r--r--odb/semantics.hxx5
-rw-r--r--odb/semantics/class-template.cxx42
-rw-r--r--odb/semantics/class-template.hxx76
-rw-r--r--odb/semantics/class.cxx10
-rw-r--r--odb/semantics/class.hxx20
-rw-r--r--odb/semantics/elements.cxx17
-rw-r--r--odb/semantics/elements.hxx35
-rw-r--r--odb/semantics/enum.cxx48
-rw-r--r--odb/semantics/enum.hxx133
-rw-r--r--odb/semantics/template.cxx66
-rw-r--r--odb/semantics/template.hxx158
-rw-r--r--odb/semantics/union-template.cxx42
-rw-r--r--odb/semantics/union-template.hxx41
-rw-r--r--odb/semantics/union.cxx33
-rw-r--r--odb/semantics/union.hxx32
17 files changed, 1354 insertions, 139 deletions
diff --git a/odb/makefile b/odb/makefile
index 825cd7b..f1dd9be 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -9,12 +9,17 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
#
cxx_ptun := plugin.cxx
-cxx_ptun += \
-semantics/class.cxx \
-semantics/derived.cxx \
-semantics/elements.cxx \
-semantics/fundamental.cxx \
-semantics/namespace.cxx \
+cxx_ptun += \
+semantics/class.cxx \
+semantics/class-template.cxx \
+semantics/derived.cxx \
+semantics/elements.cxx \
+semantics/enum.cxx \
+semantics/fundamental.cxx \
+semantics/namespace.cxx \
+semantics/template.cxx \
+semantics/union.cxx \
+semantics/union-template.cxx \
semantics/unit.cxx
# Driver units
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 0f34a5b..bb50a3f 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -139,41 +139,12 @@ private:
if (DECL_NAME (decl) != NULL_TREE)
decls_.insert (decl);
- /*
- tree type (TREE_TYPE (decl));
-
- if (TREE_CODE (type) == RECORD_TYPE)
- {
- tree name (DECL_NAME (decl));
-
- if (name != NULL_TREE)
- {
- if (DECL_ARTIFICIAL (decl))
- {
- // If we have an anonymous class typedef, use the user-
- // supplied name instead of the synthesized one. ARM
- // says that in typedef struct {} S; S becomes struct's
- // name.
- //
- if (ANON_AGGRNAME_P (name))
- {
- tree d (TYPE_NAME (type));
-
- if (d != NULL_TREE &&
- !DECL_ARTIFICIAL (d) &&
- DECL_NAME (d) != NULL_TREE &&
- !ANON_AGGRNAME_P (DECL_NAME (d)))
- {
- decls_.insert (d);
- }
- }
- else
- decls_.insert (decl);
- }
- }
- }
- */
-
+ break;
+ }
+ case TEMPLATE_DECL:
+ {
+ if (DECL_CLASS_TEMPLATE_P (decl))
+ decls_.insert (decl);
break;
}
default:
@@ -289,6 +260,7 @@ private:
}
case TEMPLATE_DECL:
{
+ emit_template_decl (decl);
break;
}
}
@@ -302,10 +274,14 @@ private:
emit_type_decl (tree decl)
{
tree t (TREE_TYPE (decl));
+ int tc (TREE_CODE (t));
+
tree decl_name (DECL_NAME (decl));
char const* name (IDENTIFIER_POINTER (decl_name));
- if (DECL_ARTIFICIAL (decl) && TREE_CODE (t) == RECORD_TYPE)
+
+ if (DECL_ARTIFICIAL (decl) &&
+ (tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE))
{
// If we have an anonymous class typedef, use the user-
// supplied name instead of the synthesized one. ARM
@@ -341,21 +317,42 @@ private:
size_t line (DECL_SOURCE_LINE (decl));
size_t clmn (DECL_SOURCE_COLUMN (decl));
- warning (0, G_ ("start class declaration %s in %s:%d"),
+ warning (0, G_ ("start %s declaration %s in %s:%d"),
+ tree_code_name[tc],
name,
DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
- class_& node (emit_class (t, file, line, clmn));
+ type* node (0);
+
+ switch (tc)
+ {
+ case RECORD_TYPE:
+ {
+ node = &emit_class<class_> (t, file, line, clmn);
+ break;
+ }
+ case UNION_TYPE:
+ {
+ node = &emit_union<union_> (t, file, line, clmn);
+ break;
+ }
+ case ENUMERAL_TYPE:
+ {
+ node = &emit_enum (t, file, line, clmn);
+ break;
+ }
+ }
if (COMPLETE_TYPE_P (t))
- unit_->new_edge<defines> (*scope_, node, name);
+ unit_->new_edge<defines> (*scope_, *node, name);
else
- unit_->new_edge<declares> (*scope_, node, name);
+ unit_->new_edge<declares> (*scope_, *node, name);
- warning (0, G_ ("end class declaration %s (%p) in %s:%d"),
+ warning (0, G_ ("end %s declaration %s (%p) in %s:%d"),
+ tree_code_name[tc],
name,
- &node,
+ node,
DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
}
@@ -365,7 +362,9 @@ private:
// class typedef case described above since we already used
// this name to define the class.
//
- if (TREE_CODE (t) == RECORD_TYPE &&
+ int tc (TREE_CODE (t));
+
+ if ((tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE) &&
TYPE_NAME (TYPE_MAIN_VARIANT (t)) == decl)
return;
@@ -387,7 +386,215 @@ private:
}
}
- class_&
+ // Emit a template declaration.
+ //
+ void
+ emit_template_decl (tree decl)
+ {
+ // Currently we only handle class/union templates.
+ //
+ tree t (TREE_TYPE (DECL_TEMPLATE_RESULT (decl)));
+ int tc (TREE_CODE (t));
+
+ warning (0, G_ ("%s template (%p) %s (%p) %s"),
+ tree_code_name[tc],
+ decl,
+ IDENTIFIER_POINTER (DECL_NAME (decl)),
+ t,
+ tree_code_name[TREE_CODE (t)]);
+
+ warning (0, G_ ("specialization:"));
+
+ for (tree s (DECL_TEMPLATE_SPECIALIZATIONS (decl));
+ s != NULL_TREE; s = TREE_CHAIN (s))
+ {
+ tree t (TREE_TYPE (s));
+ tree d (TYPE_NAME (t));
+
+ warning (0, G_ ("\tspecialization %p at %s:%d"),
+ t,
+ DECL_SOURCE_FILE (d),
+ DECL_SOURCE_LINE (d));
+ }
+
+ warning (0, G_ ("instantiations:"));
+
+ for (tree i (DECL_TEMPLATE_INSTANTIATIONS (decl));
+ i != NULL_TREE; i = TREE_CHAIN (i))
+ {
+ tree t (TREE_VALUE (i));
+ tree d (TYPE_NAME (t));
+
+ warning (0, G_ ("\tinstantiation %p at %s:%d"),
+ t,
+ DECL_SOURCE_FILE (d),
+ DECL_SOURCE_LINE (d));
+ }
+
+ char const* name (IDENTIFIER_POINTER (DECL_NAME (decl)));
+
+ warning (0, G_ ("start %s template %s in %s:%d"),
+ tree_code_name[tc],
+ name,
+ DECL_SOURCE_FILE (decl),
+ DECL_SOURCE_LINE (decl));
+
+ type_template* t_node (0);
+
+ if (tc == RECORD_TYPE)
+ t_node = &emit_class_template (decl);
+ else
+ t_node = &emit_union_template (decl);
+
+ if (COMPLETE_TYPE_P (t))
+ unit_->new_edge<defines> (*scope_, *t_node, name);
+ else
+ unit_->new_edge<declares> (*scope_, *t_node, name);
+
+ warning (0, G_ ("end %s template %s (%p) in %s:%d"),
+ tree_code_name[tc],
+ name,
+ t_node,
+ DECL_SOURCE_FILE (decl),
+ DECL_SOURCE_LINE (decl));
+ }
+
+ class_template&
+ emit_class_template (tree t, bool stub = false)
+ {
+ // See if there is a stub already for this template.
+ //
+ class_template* ct_node (0);
+
+ if (node* n = unit_->find (t))
+ {
+ ct_node = &dynamic_cast<class_template&> (*n);
+ }
+ else
+ {
+ path f (DECL_SOURCE_FILE (t));
+ size_t l (DECL_SOURCE_LINE (t));
+ size_t c (DECL_SOURCE_COLUMN (t));
+
+ ct_node = &unit_->new_node<class_template> (f, l, c);
+ unit_->insert (t, *ct_node);
+ }
+
+ tree c (TREE_TYPE (DECL_TEMPLATE_RESULT (t)));
+
+ if (stub || !COMPLETE_TYPE_P (c))
+ return *ct_node;
+
+ // Collect member declarations so that we can traverse them in
+ // the source code order. For now we are only interested in
+ // nested class template declarations.
+ //
+ decl_set decls;
+
+ for (tree d (TYPE_FIELDS (c)); d != NULL_TREE ; d = TREE_CHAIN (d))
+ {
+ switch (TREE_CODE (d))
+ {
+ case TEMPLATE_DECL:
+ {
+ if (DECL_CLASS_TEMPLATE_P (d))
+ decls.insert (d);
+ break;
+ }
+ }
+ }
+
+ scope* prev_scope (scope_);
+ scope_ = ct_node;
+
+ for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
+ i != e; ++i)
+ {
+ tree d (*i);
+
+ switch (TREE_CODE (d))
+ {
+ case TEMPLATE_DECL:
+ {
+ emit_template_decl (d);
+ break;
+ }
+ }
+ }
+
+ scope_ = prev_scope;
+ return *ct_node;
+ }
+
+ union_template&
+ emit_union_template (tree t, bool stub = false)
+ {
+ // See if there is a stub already for this template.
+ //
+ union_template* ut_node (0);
+
+ if (node* n = unit_->find (t))
+ {
+ ut_node = &dynamic_cast<union_template&> (*n);
+ }
+ else
+ {
+ path f (DECL_SOURCE_FILE (t));
+ size_t l (DECL_SOURCE_LINE (t));
+ size_t c (DECL_SOURCE_COLUMN (t));
+
+ ut_node = &unit_->new_node<union_template> (f, l, c);
+ unit_->insert (t, *ut_node);
+ }
+
+ tree u (TREE_TYPE (DECL_TEMPLATE_RESULT (t)));
+
+ if (stub || !COMPLETE_TYPE_P (u))
+ return *ut_node;
+
+ // Collect member declarations so that we can traverse them in
+ // the source code order. For now we are only interested in
+ // nested class template declarations.
+ //
+ decl_set decls;
+
+ for (tree d (TYPE_FIELDS (u)); d != NULL_TREE ; d = TREE_CHAIN (d))
+ {
+ switch (TREE_CODE (d))
+ {
+ case TEMPLATE_DECL:
+ {
+ if (DECL_CLASS_TEMPLATE_P (d))
+ decls.insert (d);
+ break;
+ }
+ }
+ }
+
+ scope* prev_scope (scope_);
+ scope_ = ut_node;
+
+ for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
+ i != e; ++i)
+ {
+ tree d (*i);
+
+ switch (TREE_CODE (d))
+ {
+ case TEMPLATE_DECL:
+ {
+ emit_template_decl (d);
+ break;
+ }
+ }
+ }
+
+ scope_ = prev_scope;
+ return *ut_node;
+ }
+
+ template <typename T>
+ T&
emit_class (tree c,
path const& file,
size_t line,
@@ -398,20 +605,20 @@ private:
// See if there is a stub already for this type.
//
- class_* class_node (0);
+ T* c_node (0);
if (node* n = unit_->find (c))
{
- class_node = &dynamic_cast<class_&> (*n);
+ c_node = &dynamic_cast<T&> (*n);
}
else
{
- class_node = &unit_->new_node<class_> (file, line, clmn);
- unit_->insert (c, *class_node);
+ c_node = &unit_->new_node<T> (file, line, clmn);
+ unit_->insert (c, *c_node);
}
if (stub || !COMPLETE_TYPE_P (c))
- return *class_node;
+ return *c_node;
// Traverse base information.
//
@@ -443,24 +650,39 @@ private:
}
bool virt (BINFO_VIRTUAL_P (bi));
- tree base (BINFO_TYPE (bi));
+ tree base (TYPE_MAIN_VARIANT (BINFO_TYPE (bi)));
+
tree base_decl (TYPE_NAME (base)); // Typedef decl for this base.
- warning (0, G_ ("\t%s%s base %s"),
+ // Find the corresponding graph node. If we cannot find one then
+ // the base is a template instantiation since an ordinary class
+ // has to be defined (complete) in order to be a base.
+ //
+ class_* b_node (0);
+ string name;
+
+ if (node* n = unit_->find (base))
+ {
+ b_node = &dynamic_cast<class_&> (*n);
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (base)));
+ }
+ else
+ {
+ b_node = &dynamic_cast<class_&> (emit_type (base, file, line, clmn));
+ name = emit_type_name (base);
+ }
+
+ unit_->new_edge<inherits> (*c_node, *b_node, a, virt);
+
+ warning (0, G_ ("\t%s%s base %s (%p)"),
a.string (),
(virt ? " virtual" : ""),
- IDENTIFIER_POINTER (DECL_NAME (base_decl)));
-
- // Find the corresponding graph node.
- //
- node* base_node (unit_->find (base));
- assert (base_node != 0);
- unit_->new_edge<inherits> (
- *class_node, dynamic_cast<class_&> (*base_node), a, virt);
+ name.c_str (),
+ static_cast<type*> (b_node));
}
- // Collect members so that we can traverse then in the source
- // code order.
+ // Collect member declarations so that we can traverse them in
+ // the source code order.
//
decl_set decls;
@@ -474,6 +696,12 @@ private:
decls.insert (d);
break;
}
+ case TEMPLATE_DECL:
+ {
+ if (DECL_CLASS_TEMPLATE_P (d))
+ decls.insert (d);
+ break;
+ }
case FIELD_DECL:
{
if (!DECL_ARTIFICIAL (d))
@@ -504,6 +732,9 @@ private:
}
}
+ scope* prev_scope (scope_);
+ scope_ = c_node;
+
for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
i != e; ++i)
{
@@ -516,6 +747,11 @@ private:
emit_type_decl (d);
break;
}
+ case TEMPLATE_DECL:
+ {
+ emit_template_decl (d);
+ break;
+ }
case FIELD_DECL:
{
tree t (TREE_TYPE (d));
@@ -534,7 +770,7 @@ private:
unit_->new_node<data_member> (file, line, clmn));
unit_->new_edge<belongs> (member_node, type_node);
- unit_->new_edge<names> (*class_node, member_node, name, a);
+ unit_->new_edge<names> (*c_node, member_node, name, a);
warning (0, G_ ("\t%s data member %s (%p) %s in %s:%i"),
a.string (),
@@ -549,7 +785,190 @@ private:
}
}
- return *class_node;
+ scope_ = prev_scope;
+ return *c_node;
+ }
+
+ template <typename T>
+ T&
+ emit_union (tree u,
+ path const& file,
+ size_t line,
+ size_t clmn,
+ bool stub = false)
+ {
+ u = TYPE_MAIN_VARIANT (u);
+
+ // See if there is a stub already for this type.
+ //
+ T* u_node (0);
+
+ if (node* n = unit_->find (u))
+ {
+ u_node = &dynamic_cast<T&> (*n);
+ }
+ else
+ {
+ u_node = &unit_->new_node<T> (file, line, clmn);
+ unit_->insert (u, *u_node);
+ }
+
+ if (stub || !COMPLETE_TYPE_P (u))
+ return *u_node;
+
+ // Collect member declarations so that we can traverse them in
+ // the source code order.
+ //
+ decl_set decls;
+
+ for (tree d (TYPE_FIELDS (u)); d != NULL_TREE ; d = TREE_CHAIN (d))
+ {
+ switch (TREE_CODE (d))
+ {
+ case TYPE_DECL:
+ {
+ if (!DECL_SELF_REFERENCE_P (d))
+ decls.insert (d);
+ break;
+ }
+ case TEMPLATE_DECL:
+ {
+ if (DECL_CLASS_TEMPLATE_P (d))
+ decls.insert (d);
+ break;
+ }
+ case FIELD_DECL:
+ {
+ if (!DECL_ARTIFICIAL (d))
+ decls.insert (d);
+ break;
+ }
+ default:
+ {
+ /*
+ tree name = DECL_NAME (d);
+
+ if (name != NULL_TREE)
+ {
+ warning (0, G_ ("\tsome declaration %s in %s:%i"),
+ IDENTIFIER_POINTER (name),
+ DECL_SOURCE_FILE (d),
+ DECL_SOURCE_LINE (d));
+ }
+ else
+ {
+ warning (0, G_ ("\tsome unnamed declaration in %s:%i"),
+ DECL_SOURCE_FILE (d),
+ DECL_SOURCE_LINE (d));
+ }
+ */
+ break;
+ }
+ }
+ }
+
+ scope* prev_scope (scope_);
+ scope_ = u_node;
+
+ for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
+ i != e; ++i)
+ {
+ tree d (*i);
+
+ switch (TREE_CODE (d))
+ {
+ case TYPE_DECL:
+ {
+ emit_type_decl (d);
+ break;
+ }
+ case TEMPLATE_DECL:
+ {
+ emit_template_decl (d);
+ break;
+ }
+ case FIELD_DECL:
+ {
+ tree t (TREE_TYPE (d));
+ char const* name (IDENTIFIER_POINTER (DECL_NAME (d)));
+
+ path file (DECL_SOURCE_FILE (d));
+ size_t line (DECL_SOURCE_LINE (d));
+ size_t clmn (DECL_SOURCE_COLUMN (d));
+
+ string type_name (emit_type_name (t));
+
+ access a (decl_access (d));
+
+ type& type_node (emit_type (t, file, line, clmn));
+ data_member& member_node (
+ unit_->new_node<data_member> (file, line, clmn));
+
+ unit_->new_edge<belongs> (member_node, type_node);
+ unit_->new_edge<names> (*u_node, member_node, name, a);
+
+ warning (0, G_ ("\t%s union member %s (%p) %s in %s:%i"),
+ a.string (),
+ type_name.c_str (),
+ &type_node,
+ name,
+ file.string ().c_str (),
+ line);
+
+ break;
+ }
+ }
+ }
+
+ scope_ = prev_scope;
+ return *u_node;
+ }
+
+ enum_&
+ emit_enum (tree e,
+ path const& file,
+ size_t line,
+ size_t clmn,
+ bool stub = false)
+ {
+ e = TYPE_MAIN_VARIANT (e);
+
+ // See if there is a stub already for this type.
+ //
+ enum_* e_node (0);
+
+ if (node* n = unit_->find (e))
+ {
+ e_node = &dynamic_cast<enum_&> (*n);
+ }
+ else
+ {
+ e_node = &unit_->new_node<enum_> (file, line, clmn);
+ unit_->insert (e, *e_node);
+ }
+
+ if (stub || !COMPLETE_TYPE_P (e))
+ return *e_node;
+
+ // Traverse enumerators.
+ //
+ for (tree er (TYPE_VALUES (e)); er != NULL_TREE ; er = TREE_CHAIN (er))
+ {
+ char const* name (IDENTIFIER_POINTER (TREE_PURPOSE (er)));
+
+ // There doesn't seem to be a way to get the proper position for
+ // each enumerator.
+ //
+ enumerator& er_node = unit_->new_node<enumerator> (file, line, clmn);
+ unit_->new_edge<enumerates> (*e_node, er_node);
+
+ warning (0, G_ ("\tenumerator %s in %s:%d"),
+ name,
+ file.string ().c_str (),
+ line);
+ }
+
+ return *e_node;
}
// Create new or find existing semantic graph type.
@@ -599,7 +1018,6 @@ private:
return q;
}
-
type&
create_type (tree t,
path const& file,
@@ -607,13 +1025,15 @@ private:
size_t clmn)
{
type* r (0);
+ int tc (TREE_CODE (t));
- switch (TREE_CODE (t))
+ switch (tc)
{
//
// User-defined types.
//
case RECORD_TYPE:
+ case UNION_TYPE:
{
tree ti (TYPE_TEMPLATE_INFO (t));
@@ -634,27 +1054,35 @@ private:
t = TYPE_MAIN_VARIANT (t);
tree d (TYPE_NAME (t));
- warning (0, G_ ("start anon/stub class declaration in %s:%d"),
+ warning (0, G_ ("start anon/stub %s declaration in %s:%d"),
+ tree_code_name[tc],
file.string ().c_str (),
line);
if (d == NULL_TREE || ANON_AGGRNAME_P (DECL_NAME (d)))
{
- r = &emit_class (t, file, line, clmn);
+ if (tc == RECORD_TYPE)
+ r = &emit_class<class_> (t, file, line, clmn);
+ else
+ r = &emit_union<union_> (t, file, line, clmn);
}
else
{
// Use the "defining" declaration's file, line, and column
// information to create the stub.
//
- r = &emit_class (t,
- path (DECL_SOURCE_FILE (d)),
- DECL_SOURCE_LINE (d),
- DECL_SOURCE_COLUMN (d),
- true);
+ path f (DECL_SOURCE_FILE (d));
+ size_t l (DECL_SOURCE_LINE (d));
+ size_t c (DECL_SOURCE_COLUMN (d));
+
+ if (tc == RECORD_TYPE)
+ r = &emit_class<class_> (t, f, l, c, true);
+ else
+ r = &emit_union<union_> (t, f, l, c, true);
}
- warning (0, G_ ("end anon/stub class declaration (%p) in %s:%d"),
+ warning (0, G_ ("end anon/stub %s declaration (%p) in %s:%d"),
+ tree_code_name[tc],
r,
file.string ().c_str (),
line);
@@ -663,50 +1091,105 @@ private:
{
// Template instantiation.
//
- /*
+ t = TYPE_MAIN_VARIANT (t);
tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE
- string id (IDENTIFIER_POINTER (DECL_NAME (decl)));
- id += '<';
+ // Get to the most general template declaration.
+ //
+ while (DECL_TEMPLATE_INFO (decl))
+ decl = DECL_TI_TEMPLATE (decl);
- tree args (INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti)));
+ type_template* t_node (0);
- int n (TREE_VEC_LENGTH (args));
-
- for (size_t i (0), n (TREE_VEC_LENGTH (args)); i < n ; ++i)
+ // Find the template node or create a stub if none exist.
+ //
+ if (node* n = unit_->find (decl))
+ t_node = &dynamic_cast<type_template&> (*n);
+ else
{
- tree a (TREE_VEC_ELT (args, i));
-
- if (i != 0)
- id += ", ";
+ warning (0, G_ ("start stub %s template for (%p) in %s:%d"),
+ tree_code_name[tc],
+ decl,
+ file.string ().c_str (),
+ line);
+
+ if (tc == RECORD_TYPE)
+ t_node = &emit_class_template (decl, true);
+ else
+ t_node = &emit_union_template (decl, true);
- // Assume type-only arguments.
- //
- id += emit_type (a);
+ warning (0, G_ ("end stub %s template (%p) in %s:%d"),
+ tree_code_name[tc],
+ t_node,
+ file.string ().c_str (),
+ line);
}
- id += '>';
+ warning (0, G_ ("start %s instantiation (%p) for template (%p) in %s:%d"),
+ tree_code_name[tc],
+ t,
+ t_node,
+ file.string ().c_str (),
+ line);
- r = id + r;
- */
- }
+ type_instantiation* i_node (0);
- break;
- }
+ if (tc == RECORD_TYPE)
+ i_node = &emit_class<class_instantiation> (t, file, line, clmn);
+ else
+ i_node = &emit_union<union_instantiation> (t, file, line, clmn);
- /*
+ warning (0, G_ ("end %s instantiation (%p) in %s:%d"),
+ tree_code_name[tc],
+ static_cast<type*> (i_node),
+ file.string ().c_str (),
+ line);
+
+ unit_->new_edge<instantiates> (*i_node, *t_node);
+ r = i_node;
+ }
- case UNION_TYPE:
- {
break;
}
case ENUMERAL_TYPE:
{
+ // The same logic as in the "ordinary class" case above
+ // applies here.
+ //
+
+ t = TYPE_MAIN_VARIANT (t);
+ tree d (TYPE_NAME (t));
+
+ warning (0, G_ ("start anon/stub %s declaration in %s:%d"),
+ tree_code_name[tc],
+ file.string ().c_str (),
+ line);
+
+ if (d == NULL_TREE || ANON_AGGRNAME_P (DECL_NAME (d)))
+ {
+ r = &emit_enum (t, file, line, clmn);
+ }
+ else
+ {
+ // Use the "defining" declaration's file, line, and column
+ // information to create the stub.
+ //
+ path f (DECL_SOURCE_FILE (d));
+ size_t l (DECL_SOURCE_LINE (d));
+ size_t c (DECL_SOURCE_COLUMN (d));
+
+ r = &emit_enum (t, f, l, c, true);
+ }
+
+ warning (0, G_ ("end anon/stub %s declaration (%p) in %s:%d"),
+ tree_code_name[tc],
+ r,
+ file.string ().c_str (),
+ line);
+
break;
}
- */
-
//
// Derived types.
//
@@ -772,15 +1255,28 @@ private:
unit_->insert (TYPE_MAIN_VARIANT (t), p);
r = &p;
}
+ else
+ {
+ r = &unit_->new_node<unsupported_type> (
+ file, line, clmn, "pointer_to_member_type");
+ warning (0, G_ ("unsupported pointer_to_member_type (%p) in %s:%d"),
+ r,
+ file.string ().c_str (),
+ line);
+ }
break;
}
default:
{
- error (G_ ("%s:%d: unexpected type %s"),
- file.string ().c_str (),
- line,
- tree_code_name[TREE_CODE (t)]);
+ r = &unit_->new_node<unsupported_type> (
+ file, line, clmn, tree_code_name[tc]);
+
+ warning (0, G_ ("unsupported %s (%p) in %s:%d"),
+ tree_code_name[tc],
+ r,
+ file.string ().c_str (),
+ line);
break;
}
}
@@ -824,13 +1320,16 @@ private:
if (CP_TYPE_RESTRICT_P (type))
r += " __restrict";
- switch (TREE_CODE (type))
+ int tc (TREE_CODE (type));
+
+ switch (tc)
{
//
// User-defined types.
//
case RECORD_TYPE:
+ case UNION_TYPE:
{
tree ti (TYPE_TEMPLATE_INFO (type));
@@ -876,16 +1375,13 @@ private:
break;
}
- /*
- case UNION_TYPE:
- {
- break;
- }
case ENUMERAL_TYPE:
{
+ type = TYPE_MAIN_VARIANT (type);
+ tree decl (TYPE_NAME (type));
+ r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r;
break;
}
- */
//
// Derived types.
@@ -946,6 +1442,8 @@ private:
tree t (TREE_TYPE (type));
r = emit_type_name (t) + "*" + r;
}
+ else
+ r = "<pointer_to_member_type>";
break;
}
@@ -966,7 +1464,7 @@ private:
}
default:
{
- r = "<unsupported>";
+ r = "<" + string (tree_code_name[tc]) + ">";
break;
}
}
diff --git a/odb/semantics.hxx b/odb/semantics.hxx
index 46350be..c30bece 100644
--- a/odb/semantics.hxx
+++ b/odb/semantics.hxx
@@ -7,10 +7,15 @@
#define ODB_SEMANTICS_HXX
#include <semantics/class.hxx>
+#include <semantics/class-template.hxx>
#include <semantics/derived.hxx>
#include <semantics/elements.hxx>
+#include <semantics/enum.hxx>
#include <semantics/fundamental.hxx>
#include <semantics/namespace.hxx>
+#include <semantics/template.hxx>
+#include <semantics/union.hxx>
+#include <semantics/union-template.hxx>
#include <semantics/unit.hxx>
#endif // ODB_SEMANTICS_HXX
diff --git a/odb/semantics/class-template.cxx b/odb/semantics/class-template.cxx
new file mode 100644
index 0000000..05deef8
--- /dev/null
+++ b/odb/semantics/class-template.cxx
@@ -0,0 +1,42 @@
+// file : odb/semantics/class-template.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cutl/compiler/type-info.hxx>
+
+#include <semantics/class-template.hxx>
+
+namespace semantics
+{
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // class_template
+ //
+ {
+ type_info ti (typeid (class_template));
+ ti.add_base (typeid (type_template));
+ ti.add_base (typeid (scope));
+ insert (ti);
+ }
+
+ // class_instantiation
+ //
+ {
+ type_info ti (typeid (class_instantiation));
+ ti.add_base (typeid (class_));
+ ti.add_base (typeid (type_instantiation));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+}
diff --git a/odb/semantics/class-template.hxx b/odb/semantics/class-template.hxx
new file mode 100644
index 0000000..6443a19
--- /dev/null
+++ b/odb/semantics/class-template.hxx
@@ -0,0 +1,76 @@
+// file : odb/semantics/class-template.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_CLASS_TEMPLATE_HXX
+#define ODB_SEMANTICS_CLASS_TEMPLATE_HXX
+
+#include <semantics/elements.hxx>
+#include <semantics/class.hxx>
+#include <semantics/template.hxx>
+
+namespace semantics
+{
+ class class_template: public type_template, public scope
+ {
+ private:
+ typedef std::vector<inherits*> inherits_list;
+
+ public:
+ typedef inherits_list::const_iterator inherits_iterator;
+
+ inherits_iterator
+ inherits_begin () const
+ {
+ return inherits_.begin ();
+ }
+
+ inherits_iterator
+ inherits_end () const
+ {
+ return inherits_.end ();
+ }
+
+ public:
+ class_template (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ void
+ add_edge_left (inherits& e)
+ {
+ inherits_.push_back (&e);
+ }
+
+ void
+ add_edge_right (inherits&)
+ {
+ }
+
+ using scope::add_edge_left;
+ using scope::add_edge_right;
+
+ // Resolve conflict between scope::scope and nameable::scope.
+ //
+ using nameable::scope;
+
+ private:
+ inherits_list inherits_;
+ };
+
+ class class_instantiation: public class_, public type_instantiation
+ {
+ public:
+ class_instantiation (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ using class_::add_edge_left;
+ using type_instantiation::add_edge_left;
+ };
+}
+
+#endif // ODB_SEMANTICS_CLASS_TEMPLATE_HXX
diff --git a/odb/semantics/class.cxx b/odb/semantics/class.cxx
index 5575745..7462d7c 100644
--- a/odb/semantics/class.cxx
+++ b/odb/semantics/class.cxx
@@ -19,15 +19,6 @@ namespace semantics
{
using compiler::type_info;
- // data_member
- //
- {
- type_info ti (typeid (data_member));
- ti.add_base (typeid (nameable));
- ti.add_base (typeid (instance));
- insert (ti);
- }
-
// inherits
//
{
@@ -40,6 +31,7 @@ namespace semantics
//
{
type_info ti (typeid (class_));
+ ti.add_base (typeid (type));
ti.add_base (typeid (scope));
insert (ti);
}
diff --git a/odb/semantics/class.hxx b/odb/semantics/class.hxx
index d4a0900..bbe4687 100644
--- a/odb/semantics/class.hxx
+++ b/odb/semantics/class.hxx
@@ -13,19 +13,6 @@ namespace semantics
{
class class_;
- //
- //
- class data_member: public nameable, public instance
- {
- public:
- data_member (path const& file, size_t line, size_t column)
- : node (file, line, column)
- {
- }
- };
-
- //
- //
class inherits: public edge
{
public:
@@ -83,7 +70,7 @@ namespace semantics
//
//
- class class_: public type, public scope
+ class class_: public virtual type, public scope
{
private:
typedef std::vector<inherits*> inherits_list;
@@ -127,6 +114,11 @@ namespace semantics
//
using nameable::scope;
+ protected:
+ class_ ()
+ {
+ }
+
private:
inherits_list inherits_;
};
diff --git a/odb/semantics/elements.cxx b/odb/semantics/elements.cxx
index d14835c..caed01e 100644
--- a/odb/semantics/elements.cxx
+++ b/odb/semantics/elements.cxx
@@ -149,6 +149,23 @@ namespace semantics
ti.add_base (typeid (node));
insert (ti);
}
+
+ // data_member
+ //
+ {
+ type_info ti (typeid (data_member));
+ ti.add_base (typeid (nameable));
+ ti.add_base (typeid (instance));
+ insert (ti);
+ }
+
+ // unsupported_type
+ //
+ {
+ type_info ti (typeid (unsupported_type));
+ ti.add_base (typeid (type));
+ insert (ti);
+ }
}
} init_;
}
diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx
index 0b89831..97f386f 100644
--- a/odb/semantics/elements.hxx
+++ b/odb/semantics/elements.hxx
@@ -543,6 +543,41 @@ namespace semantics
private:
belongs_type* belongs_;
};
+
+ // Data member for class and union types.
+ //
+ class data_member: public nameable, public instance
+ {
+ public:
+ data_member (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+ };
+
+ // Unsupported type.
+ //
+ class unsupported_type: public type
+ {
+ public:
+ string const&
+ type_name () const
+ {
+ return type_name_;
+ }
+
+ public:
+ unsupported_type (path const& file,
+ size_t line,
+ size_t column,
+ string const& type_name)
+ : node (file, line, column), type_name_ (type_name)
+ {
+ }
+
+ private:
+ string const type_name_;
+ };
}
#include <semantics/elements.ixx>
diff --git a/odb/semantics/enum.cxx b/odb/semantics/enum.cxx
new file mode 100644
index 0000000..ab19c70
--- /dev/null
+++ b/odb/semantics/enum.cxx
@@ -0,0 +1,48 @@
+// file : odb/semantics/enum.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cutl/compiler/type-info.hxx>
+
+#include <semantics/enum.hxx>
+
+namespace semantics
+{
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // enumerates
+ //
+ {
+ type_info ti (typeid (enumerates));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // enumerator
+ //
+ {
+ type_info ti (typeid (enumerator));
+ ti.add_base (typeid (instance));
+ insert (ti);
+ }
+
+ // enum_
+ //
+ {
+ type_info ti (typeid (enum_));
+ ti.add_base (typeid (type));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+}
diff --git a/odb/semantics/enum.hxx b/odb/semantics/enum.hxx
new file mode 100644
index 0000000..e628ad9
--- /dev/null
+++ b/odb/semantics/enum.hxx
@@ -0,0 +1,133 @@
+// file : odb/semantics/enum.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_ENUM_HXX
+#define ODB_SEMANTICS_ENUM_HXX
+
+#include <vector>
+#include <semantics/elements.hxx>
+
+namespace semantics
+{
+ class enum_;
+ class enumerator;
+
+ class enumerates: public edge
+ {
+ public:
+ typedef semantics::enum_ enum_type;
+ typedef semantics::enumerator enumerator_type;
+
+ enum_type&
+ enum_ () const
+ {
+ return *enum__;
+ }
+
+ enumerator_type&
+ enumerator () const
+ {
+ return *enumerator_;
+ }
+
+ public:
+ enumerates ()
+ {
+ }
+
+ void
+ set_left_node (enum_type& n)
+ {
+ enum__ = &n;
+ }
+
+ void
+ set_right_node (enumerator_type& n)
+ {
+ enumerator_ = &n;
+ }
+
+ protected:
+ enum_type* enum__;
+ enumerator_type* enumerator_;
+ };
+
+ //
+ //
+ class enumerator: public instance
+ {
+ public:
+ typedef semantics::enum_ enum_type;
+
+ enum_type&
+ enum_ () const
+ {
+ return enumerated_->enum_ ();
+ }
+
+ enumerates&
+ enumerated () const
+ {
+ return *enumerated_;
+ }
+
+ public:
+ enumerator (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ void
+ add_edge_right (enumerates& e)
+ {
+ enumerated_ = &e;
+ }
+
+ using instance::add_edge_right;
+
+ private:
+ enumerates* enumerated_;
+ };
+
+ //
+ //
+ class enum_: public type
+ {
+ private:
+ typedef std::vector<enumerates*> enumerates_list;
+
+ public:
+ typedef enumerates_list::const_iterator enumerates_iterator;
+
+ enumerates_iterator
+ enumerates_begin () const
+ {
+ return enumerates_.begin ();
+ }
+
+ enumerates_iterator
+ enumerates_end () const
+ {
+ return enumerates_.end ();
+ }
+
+ public:
+ enum_ (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ void
+ add_edge_left (enumerates& e)
+ {
+ enumerates_.push_back (&e);
+ }
+
+ private:
+ enumerates_list enumerates_;
+ };
+}
+
+#endif // ODB_SEMANTICS_ENUM_HXX
diff --git a/odb/semantics/template.cxx b/odb/semantics/template.cxx
new file mode 100644
index 0000000..4882aa3
--- /dev/null
+++ b/odb/semantics/template.cxx
@@ -0,0 +1,66 @@
+// file : odb/semantics/template.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cutl/compiler/type-info.hxx>
+
+#include <semantics/template.hxx>
+
+namespace semantics
+{
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // template_
+ //
+ {
+ type_info ti (typeid (template_));
+ ti.add_base (typeid (nameable));
+ insert (ti);
+ }
+
+ // instantiates
+ //
+ {
+ type_info ti (typeid (instantiates));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // instantiation
+ //
+ {
+ type_info ti (typeid (instantiation));
+ ti.add_base (typeid (node));
+ insert (ti);
+ }
+
+ // type_template
+ //
+ {
+ type_info ti (typeid (type_template));
+ ti.add_base (typeid (template_));
+ insert (ti);
+ }
+
+ // type_instantiation
+ //
+ {
+ type_info ti (typeid (type_instantiation));
+ ti.add_base (typeid (type));
+ ti.add_base (typeid (instantiation));
+ insert (ti);
+ }
+
+ }
+ } init_;
+ }
+}
diff --git a/odb/semantics/template.hxx b/odb/semantics/template.hxx
new file mode 100644
index 0000000..1357dbf
--- /dev/null
+++ b/odb/semantics/template.hxx
@@ -0,0 +1,158 @@
+// file : odb/semantics/template.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_TEMPLATE_HXX
+#define ODB_SEMANTICS_TEMPLATE_HXX
+
+#include <vector>
+#include <semantics/elements.hxx>
+
+namespace semantics
+{
+ //
+ //
+ class instantiates;
+
+ class template_: public virtual nameable
+ {
+ typedef std::vector<instantiates*> instantiated;
+
+ public:
+ typedef
+ pointer_iterator<instantiated::const_iterator>
+ instantiated_iterator;
+
+ instantiated_iterator
+ instantiated_begin () const
+ {
+ return instantiated_.begin ();
+ }
+
+ instantiated_iterator
+ instantiated_end () const
+ {
+ return instantiated_.end ();
+ }
+
+ public:
+ void
+ add_edge_right (instantiates& e)
+ {
+ instantiated_.push_back (&e);
+ }
+
+ using nameable::add_edge_right;
+
+ protected:
+ template_ ()
+ {
+ }
+
+ private:
+ instantiated instantiated_;
+ };
+
+ //
+ //
+ class instantiation;
+
+ class instantiates: public edge
+ {
+ public:
+ typedef semantics::template_ template_type;
+ typedef semantics::instantiation instantiation_type;
+
+ template_type&
+ template_ () const
+ {
+ return *template__;
+ }
+
+ instantiation_type&
+ instantiation () const
+ {
+ return *instantiation_;
+ }
+
+ public:
+ instantiates ()
+ {
+ }
+
+ void
+ set_left_node (instantiation_type& n)
+ {
+ instantiation_ = &n;
+ }
+
+ void
+ set_right_node (template_type& n)
+ {
+ template__ = &n;
+ }
+
+ private:
+ template_type* template__;
+ instantiation_type* instantiation_;
+ };
+
+ //
+ //
+ class instantiation: public virtual node
+ {
+ public:
+ typedef semantics::template_ template_type;
+ typedef semantics::instantiates instantiates_type;
+
+ template_type&
+ template_ () const
+ {
+ return instantiates_->template_ ();
+ }
+
+ instantiates_type&
+ instantiates () const
+ {
+ return *instantiates_;
+ }
+
+ public:
+ void
+ add_edge_left (instantiates_type& e)
+ {
+ instantiates_ = &e;
+ }
+
+ protected:
+ instantiation ()
+ {
+ }
+
+ private:
+ instantiates_type* instantiates_;
+ };
+
+ //
+ // Type template and instantiation.
+ //
+
+ class type_template: public template_
+ {
+ protected:
+ type_template ()
+ {
+ }
+ };
+
+ class type_instantiation: public virtual type, public instantiation
+ {
+ protected:
+ type_instantiation ()
+ {
+ }
+ };
+}
+
+#endif // ODB_SEMANTICS_TEMPLATE_HXX
diff --git a/odb/semantics/union-template.cxx b/odb/semantics/union-template.cxx
new file mode 100644
index 0000000..a83748f
--- /dev/null
+++ b/odb/semantics/union-template.cxx
@@ -0,0 +1,42 @@
+// file : odb/semantics/union-template.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cutl/compiler/type-info.hxx>
+
+#include <semantics/union-template.hxx>
+
+namespace semantics
+{
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // union_template
+ //
+ {
+ type_info ti (typeid (union_template));
+ ti.add_base (typeid (type_template));
+ ti.add_base (typeid (scope));
+ insert (ti);
+ }
+
+ // union_instantiation
+ //
+ {
+ type_info ti (typeid (union_instantiation));
+ ti.add_base (typeid (union_));
+ ti.add_base (typeid (type_instantiation));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+}
diff --git a/odb/semantics/union-template.hxx b/odb/semantics/union-template.hxx
new file mode 100644
index 0000000..1aaadb7
--- /dev/null
+++ b/odb/semantics/union-template.hxx
@@ -0,0 +1,41 @@
+// file : odb/semantics/union-template.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_UNION_TEMPLATE_HXX
+#define ODB_SEMANTICS_UNION_TEMPLATE_HXX
+
+#include <semantics/elements.hxx>
+#include <semantics/union.hxx>
+#include <semantics/template.hxx>
+
+namespace semantics
+{
+ class union_template: public type_template, public scope
+ {
+ public:
+ union_template (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ // Resolve conflict between scope::scope and nameable::scope.
+ //
+ using nameable::scope;
+ };
+
+ class union_instantiation: public union_, public type_instantiation
+ {
+ public:
+ union_instantiation (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ using union_::add_edge_left;
+ using type_instantiation::add_edge_left;
+ };
+}
+
+#endif // ODB_SEMANTICS_UNION_TEMPLATE_HXX
diff --git a/odb/semantics/union.cxx b/odb/semantics/union.cxx
new file mode 100644
index 0000000..a4e62a1
--- /dev/null
+++ b/odb/semantics/union.cxx
@@ -0,0 +1,33 @@
+// file : odb/semantics/union.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cutl/compiler/type-info.hxx>
+
+#include <semantics/union.hxx>
+
+namespace semantics
+{
+ // type info
+ //
+ namespace
+ {
+ struct init
+ {
+ init ()
+ {
+ using compiler::type_info;
+
+ // union_
+ //
+ {
+ type_info ti (typeid (union_));
+ ti.add_base (typeid (type));
+ ti.add_base (typeid (scope));
+ insert (ti);
+ }
+ }
+ } init_;
+ }
+}
diff --git a/odb/semantics/union.hxx b/odb/semantics/union.hxx
new file mode 100644
index 0000000..2873d97
--- /dev/null
+++ b/odb/semantics/union.hxx
@@ -0,0 +1,32 @@
+// file : odb/semantics/union.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_SEMANTICS_UNION_HXX
+#define ODB_SEMANTICS_UNION_HXX
+
+#include <semantics/elements.hxx>
+
+namespace semantics
+{
+ class union_: public virtual type, public scope
+ {
+ public:
+ union_ (path const& file, size_t line, size_t column)
+ : node (file, line, column)
+ {
+ }
+
+ // Resolve conflict between scope::scope and nameable::scope.
+ //
+ using nameable::scope;
+
+ protected:
+ union_ ()
+ {
+ }
+ };
+}
+
+#endif // ODB_SEMANTICS_UNION_HXX