summaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-04-02 18:41:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-04-02 18:41:18 +0200
commit15e6fd2b0976f82eb1ef10d2d26912d12e4f0a99 (patch)
treeebec92c4dd0ef6998c22fbe7e0971463615973db /odb
parent33e79981967fe82d392c90974031abd444e1f9f8 (diff)
Implement pragma support
Diffstat (limited to 'odb')
-rw-r--r--odb/gcc.hxx9
-rw-r--r--odb/makefile1
-rw-r--r--odb/plugin.cxx346
-rw-r--r--odb/pragma.cxx274
-rw-r--r--odb/pragma.hxx89
5 files changed, 657 insertions, 62 deletions
diff --git a/odb/gcc.hxx b/odb/gcc.hxx
index ab54707..9d1e3bc 100644
--- a/odb/gcc.hxx
+++ b/odb/gcc.hxx
@@ -29,7 +29,16 @@ extern "C"
#include "diagnostic.h"
#include "c-common.h"
+#include "c-pragma.h"
#include "cp/cp-tree.h"
}
+#ifndef LOCATION_COLUMN
+#define LOCATION_COLUMN(LOC) (expand_location (LOC).column)
+#endif
+
+#ifndef DECL_SOURCE_COLUMN
+#define DECL_SOURCE_COLUMN(NODE) LOCATION_COLUMN (DECL_SOURCE_LOCATION (NODE))
+#endif
+
#endif // ODB_GCC_TREE_HXX
diff --git a/odb/makefile b/odb/makefile
index b66804d..b7c9209 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -11,6 +11,7 @@ cxx_ptun := \
context.cxx \
generator.cxx \
plugin.cxx \
+pragma.cxx \
source.cxx
cxx_ptun += \
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 06c7abd..98d12d8 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -13,18 +13,11 @@
#include <sstream>
#include <iostream>
+#include <odb/pragma.hxx>
#include <odb/options.hxx>
#include <odb/semantics.hxx>
#include <odb/generator.hxx>
-#ifndef LOCATION_COLUMN
-#define LOCATION_COLUMN(LOC) (expand_location (LOC).column)
-#endif
-
-#ifndef DECL_SOURCE_COLUMN
-#define DECL_SOURCE_COLUMN(NODE) LOCATION_COLUMN (DECL_SOURCE_LOCATION (NODE))
-#endif
-
using namespace std;
using namespace semantics;
@@ -33,10 +26,16 @@ int plugin_is_GPL_compatible;
class parser
{
public:
- typedef semantics::access access;
-
- parser (options const& ops)
- : ops_ (ops), trace (ops.trace ()), ts (cerr)
+ class failed {};
+
+ parser (options const& ops,
+ loc_pragmas const& lp,
+ decl_pragmas const& dp)
+ : ops_ (ops),
+ loc_pragmas_ (lp),
+ decl_pragmas_ (dp),
+ trace (ops.trace ()),
+ ts (cerr)
{
}
@@ -46,6 +45,7 @@ public:
auto_ptr<unit> u (new unit (main_file));
unit_ = u.get ();
scope_ = unit_;
+ error_ = 0;
// Define fundamental types.
//
@@ -72,12 +72,71 @@ public:
// code order.
//
collect (global_scope);
+
+ // Add namespace-level location pragmas if any.
+ //
+ {
+ loc_pragmas::const_iterator i (loc_pragmas_.find (global_namespace));
+
+ if (i != loc_pragmas_.end ())
+ decls_.insert (i->second.begin (), i->second.end ());
+ }
+
+ // Construct the semantic graph.
+ //
emit ();
+ if (error_ > 0)
+ throw failed ();
+
return u;
}
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.
+ //
+ struct tree_decl
+ {
+ tree decl;
+ 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) {}
+
+ bool
+ 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);
+
+ if (xloc != yloc)
+ return xloc < yloc;
+
+ size_t xl (LOCATION_LINE (xloc));
+ size_t yl (LOCATION_LINE (yloc));
+
+ if (xl != yl)
+ return xl < yl;
+
+ size_t xc (LOCATION_COLUMN (xloc));
+ size_t yc (LOCATION_COLUMN (yloc));
+
+ if (xc != yc)
+ return xc < yc;
+
+ return false;
+ }
+ };
+
+ typedef std::multiset<tree_decl> decl_set;
+
+private:
void
collect (tree ns)
{
@@ -135,10 +194,15 @@ private:
void
emit ()
{
- for (decl_set::const_iterator i (decls_.begin ()), e (decls_.end ());
- i != e; ++i)
+ for (decl_set::const_iterator b (decls_.begin ()), i (b),
+ e (decls_.end ()); i != e; ++i)
{
- tree decl (*i);
+ // Skip pragmas.
+ //
+ if (i->prag)
+ continue;
+
+ tree decl (i->decl);
// Get this declaration's namespace and unwind our scope until
// we find a common prefix of namespaces.
@@ -193,7 +257,14 @@ private:
{
case TYPE_DECL:
{
- emit_type_decl (decl);
+ type* n (emit_type_decl (decl));
+
+ // If this is a named class-type definition, then handle
+ // the pragmas.
+ //
+ if (n != 0)
+ process_pragmas (n->tree_node (), *n, n->name (), b, i, e);
+
break;
}
case TEMPLATE_DECL:
@@ -203,12 +274,17 @@ private:
}
}
}
+
+ // Diagnose any position pragmas that haven't been associated.
+ //
+ diagnose_unassoc_pragmas (decls_);
}
- // Emit a type declaration. This is either a class definition/declaration
- // or a typedef.
+ // Emit a type declaration. This is either a named class-type definition/
+ // declaration or a typedef. In the former case the function returns the
+ // newly created type node. In the latter case it returns 0.
//
- void
+ type*
emit_type_decl (tree decl)
{
tree t (TREE_TYPE (decl));
@@ -247,7 +323,7 @@ private:
// covered by the typedef handling code below. The second
// case will be covere by emit_type().
//
- return;
+ return 0;
}
}
@@ -305,6 +381,8 @@ private:
unit_->new_edge<defines> (*scope_, *node, name);
else
unit_->new_edge<declares> (*scope_, *node, name);
+
+ return node;
}
else
{
@@ -316,7 +394,7 @@ private:
if ((tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE) &&
TYPE_NAME (TYPE_MAIN_VARIANT (t)) == decl)
- return;
+ return 0;
path f (DECL_SOURCE_FILE (decl));
size_t l (DECL_SOURCE_LINE (decl));
@@ -333,6 +411,8 @@ private:
<< DECL_SOURCE_FILE (decl) << ":"
<< DECL_SOURCE_LINE (decl) << endl;
}
+
+ return 0;
}
}
@@ -457,7 +537,12 @@ private:
for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
i != e; ++i)
{
- tree d (*i);
+ // Skip pragmas.
+ //
+ if (i->prag)
+ continue;
+
+ tree d (i->decl);
switch (TREE_CODE (d))
{
@@ -469,6 +554,10 @@ private:
}
}
+ // Diagnose any position pragmas that haven't been associated.
+ //
+ diagnose_unassoc_pragmas (decls);
+
scope_ = prev_scope;
return *ct_node;
}
@@ -524,7 +613,12 @@ private:
for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
i != e; ++i)
{
- tree d (*i);
+ // Skip pragmas.
+ //
+ if (i->prag)
+ continue;
+
+ tree d (i->decl);
switch (TREE_CODE (d))
{
@@ -536,6 +630,10 @@ private:
}
}
+ // Diagnose any position pragmas that haven't been associated.
+ //
+ diagnose_unassoc_pragmas (decls);
+
scope_ = prev_scope;
return *ut_node;
}
@@ -660,19 +758,40 @@ private:
}
}
+ // Add location pragmas if any.
+ //
+ {
+ loc_pragmas::const_iterator i (loc_pragmas_.find (c));
+
+ if (i != loc_pragmas_.end ())
+ decls.insert (i->second.begin (), i->second.end ());
+ }
+
scope* prev_scope (scope_);
scope_ = c_node;
- for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
+ for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ());
i != e; ++i)
{
- tree d (*i);
+ // Skip pragmas.
+ //
+ if (i->prag)
+ continue;
+
+ tree d (i->decl);
switch (TREE_CODE (d))
{
case TYPE_DECL:
{
- emit_type_decl (d);
+ type* n (emit_type_decl (d));
+
+ // If this is a named class-type definition, then handle
+ // the pragmas.
+ //
+ if (n != 0)
+ process_pragmas (n->tree_node (), *n, n->name (), b, i, e);
+
break;
}
case TEMPLATE_DECL:
@@ -720,11 +839,19 @@ private:
<< file << ":" << line << endl;
}
+ // Process pragmas that may be associated with this field.
+ //
+ process_pragmas (d, member_node, name, b, i, e);
+
break;
}
}
}
+ // Diagnose any position pragmas that haven't been associated.
+ //
+ diagnose_unassoc_pragmas (decls);
+
scope_ = prev_scope;
return *c_node;
}
@@ -786,19 +913,40 @@ private:
}
}
+ // Add location pragmas if any.
+ //
+ {
+ loc_pragmas::const_iterator i (loc_pragmas_.find (u));
+
+ if (i != loc_pragmas_.end ())
+ decls.insert (i->second.begin (), i->second.end ());
+ }
+
scope* prev_scope (scope_);
scope_ = u_node;
- for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
+ for (decl_set::const_iterator b (decls.begin ()), i (b), e (decls.end ());
i != e; ++i)
{
- tree d (*i);
+ // Skip pragmas.
+ //
+ if (i->prag)
+ continue;
+
+ tree d (i->decl);
switch (TREE_CODE (d))
{
case TYPE_DECL:
{
- emit_type_decl (d);
+ type* n (emit_type_decl (d));
+
+ // If this is a named class-type definition, then handle
+ // the pragmas.
+ //
+ if (n != 0)
+ process_pragmas (n->tree_node (), *n, n->name (), b, i, e);
+
break;
}
case TEMPLATE_DECL:
@@ -833,11 +981,19 @@ private:
<< file << ":" << line << endl;
}
+ // Process pragmas that may be associated with this field.
+ //
+ process_pragmas (d, member_node, name, b, i, e);
+
break;
}
}
}
+ // Diagnose any position pragmas that haven't been associated.
+ //
+ diagnose_unassoc_pragmas (decls);
+
scope_ = prev_scope;
return *u_node;
}
@@ -1149,10 +1305,11 @@ private:
}
else
{
- error (G_ ("%s:%d: non-integer array index %s"),
- file.string ().c_str (),
- line,
- tree_code_name[TREE_CODE (max)]);
+ cerr << file << ':' << line << ':' << clmn << ": error: "
+ << " non-integer array index "
+ << tree_code_name[TREE_CODE (max)];
+
+ throw failed ();
}
}
@@ -1342,8 +1499,9 @@ private:
}
else
{
- error (G_ ("non-integer array index %s"),
- tree_code_name[TREE_CODE (type)]);
+ // Non-integer array index which we do not support. The
+ // error has been/will be issued in emit_type.
+ //
}
}
@@ -1403,6 +1561,80 @@ private:
return r;
}
+ void
+ process_pragmas (tree t,
+ 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.
+ //
+ 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 != cur; ++i)
+ {
+ assert (!i->assoc);
+
+ if (check_decl_type (t, name, i->prag->name, i->prag->loc))
+ prags.insert (*i->prag);
+ else
+ error_++;
+
+ i->assoc = true; // Mark this pragma 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.
+ //
+ {
+ decl_pragmas::const_iterator i (decl_pragmas_.find (t));
+
+ if (i != decl_pragmas_.end ())
+ prags.insert (i->second.begin (), i->second.end ());
+ }
+
+ // Finally, copy the resulting pragma set to context.
+ //
+ for (pragma_set::iterator i (prags.begin ()); i != prags.end (); ++i)
+ {
+ if (trace)
+ ts << "\t\t pragma " << i->name << " (" << i->value << ")"
+ << endl;
+
+ node.set (i->name, i->value);
+ }
+ }
+
+ void
+ diagnose_unassoc_pragmas (decl_set const& decls)
+ {
+ for (decl_set::const_iterator i (decls.begin ()), e (decls.end ());
+ i != e; ++i)
+ {
+ if (i->prag && !i->assoc)
+ {
+ pragma const& p (*i->prag);
+ error_at (p.loc, "odb pragma %qs is not associated with a declaration",
+ p.name.c_str ());
+ error_++;
+ }
+ }
+ }
// Return declaration's fully-qualified scope name (e.g., ::foo::bar).
//
@@ -1456,6 +1688,8 @@ private:
private:
options const& ops_;
+ loc_pragmas const& loc_pragmas_;
+ decl_pragmas const& decl_pragmas_;
bool trace;
ostream& ts;
@@ -1463,33 +1697,8 @@ private:
unit* unit_;
scope* scope_;
- struct location_comparator
- {
- bool operator() (tree x, tree y) const
- {
- location_t xloc (DECL_SOURCE_LOCATION (x));
- location_t yloc (DECL_SOURCE_LOCATION (y));
-
- if (xloc != yloc)
- return xloc < yloc;
-
- size_t xl (LOCATION_LINE (xloc));
- size_t yl (LOCATION_LINE (yloc));
-
- if (xl != yl)
- return xl < yl;
-
- size_t xc (LOCATION_COLUMN (xloc));
- size_t yc (LOCATION_COLUMN (yloc));
-
- if (xc != yc)
- return xc < yc;
-
- return false;
- }
- };
+ size_t error_;
- typedef std::multiset<tree, location_comparator> decl_set;
decl_set decls_;
typedef std::map<string, fund_type*> fund_type_map;
@@ -1511,13 +1720,19 @@ gate_callback (void* gcc_data, void*)
try
{
- parser p (*options_);
+ parser p (*options_, loc_pragmas_, decl_pragmas_);
path file (main_input_filename);
auto_ptr<unit> u (p.parse (global_namespace, file));
generator g;
g.generate (*options_, *u, file);
}
+ catch (parser::failed const&)
+ {
+ // Diagnostics has aready been issued.
+ //
+ r = 1;
+ }
catch (generator::failed const&)
{
// Diagnostics has aready been issued.
@@ -1576,6 +1791,13 @@ plugin_init (struct plugin_name_args *plugin_info,
//
asm_file_name = HOST_BIT_BUCKET;
+ // Register callbacks.
+ //
+ register_callback (plugin_info->base_name,
+ PLUGIN_PRAGMAS,
+ register_odb_pragmas,
+ 0);
+
register_callback (plugin_info->base_name,
PLUGIN_OVERRIDE_GATE,
&gate_callback,
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
new file mode 100644
index 0000000..33d69f0
--- /dev/null
+++ b/odb/pragma.cxx
@@ -0,0 +1,274 @@
+// file : odb/pragma.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 <odb/pragma.hxx>
+
+using namespace std;
+
+loc_pragmas loc_pragmas_;
+decl_pragmas decl_pragmas_;
+
+static tree
+parse_scoped_name (tree& t,
+ cpp_ttype& tt,
+ string& name,
+ bool is_type,
+ string const& prag)
+{
+ tree scope, id;
+
+ if (tt == CPP_SCOPE)
+ {
+ name += "::";
+ scope = global_namespace;
+ tt = pragma_lex (&t);
+ }
+ else
+ scope = current_scope ();
+
+ while (true)
+ {
+ if (tt != CPP_NAME)
+ {
+ error ("invalid name in odb pragma %qs", prag.c_str ());
+ return 0;
+ }
+
+ id = t;
+ name += IDENTIFIER_POINTER (t);
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_SCOPE)
+ {
+ scope = lookup_qualified_name (scope, id, false, false);
+
+ if (scope == error_mark_node)
+ {
+ error ("unable to resolve name %qs in odb pragma %qs",
+ name.c_str (), prag.c_str ());
+ return 0;
+ }
+
+ if (TREE_CODE (scope) == TYPE_DECL)
+ scope = TREE_TYPE (scope);
+
+ name += "::";
+ tt = pragma_lex (&t);
+ }
+ else
+ break;
+ }
+
+ tree decl (lookup_qualified_name (scope, id, is_type, false));
+
+ if (decl == error_mark_node)
+ {
+ error ("unable to resolve name %qs in odb pragma %qs",
+ name.c_str (), prag.c_str ());
+ return 0;
+ }
+
+ // Get the actual type if this is a TYPE_DECL.
+ //
+ if (is_type && TREE_CODE (decl) == TYPE_DECL)
+ decl = TREE_TYPE (decl);
+
+ return decl;
+}
+
+bool
+check_decl_type (tree d, string const& name, string const& p, location_t l)
+{
+ int tc (TREE_CODE (d));
+ char const* pc (p.c_str ());
+
+ if (p == "column")
+ {
+ if (tc != FIELD_DECL)
+ {
+ error_at (l, "name %qs in odb pragma %qs does not refer to "
+ "a member variable", name.c_str (), pc);
+ return false;
+ }
+ }
+ else if (p == "table")
+ {
+ if (tc != RECORD_TYPE)
+ {
+ error_at (l, "name %qs in odb pragma %qs does not refer to a class",
+ name.c_str (), pc);
+ return false;
+ }
+ }
+ else
+ {
+ error ("unknown odb pragma %qs", pc);
+ return false;
+ }
+
+ return true;
+}
+
+static void
+handle_pragma (string const& p)
+{
+ tree t;
+ cpp_ttype tt;
+ char const* pc (p.c_str ());
+
+ string val;
+ tree decl (0);
+ location_t loc (input_location);
+
+ if (p == "column")
+ {
+ // column ([<identifier>,] "<name>")
+ //
+
+ if (pragma_lex (&t) != CPP_OPEN_PAREN)
+ {
+ error ("%qs expected after odb pragma %qs", "(", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_NAME || tt == CPP_SCOPE)
+ {
+ string name;
+ decl = parse_scoped_name (t, tt, name, false, p);
+
+ if (decl == 0)
+ return;
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (!check_decl_type (decl, name, p, loc))
+ return;
+
+ if (tt != CPP_COMMA)
+ {
+ error ("column name expected in odb pragma %qs", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
+
+ if (tt != CPP_STRING)
+ {
+ error ("column name expected in odb pragma %qs", pc);
+ return;
+ }
+
+ val = TREE_STRING_POINTER (t);
+
+ if (pragma_lex (&t) != CPP_CLOSE_PAREN)
+ {
+ error ("%qs expected at the end of odb pragma %qs", ")", pc);
+ return;
+ }
+ }
+ else if (p == "table")
+ {
+ // table ([<identifier>,] "<name>")
+ //
+
+ if (pragma_lex (&t) != CPP_OPEN_PAREN)
+ {
+ error ("%qs expected after odb pragma %qs", "(", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_NAME || tt == CPP_SCOPE)
+ {
+ string name;
+ decl = parse_scoped_name (t, tt, name, true, p);
+
+ if (decl == 0)
+ return;
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (!check_decl_type (decl, name, p, loc))
+ return;
+
+ if (tt != CPP_COMMA)
+ {
+ error ("table name expected in odb pragma %qs", pc);
+ return;
+ }
+
+ tt = pragma_lex (&t);
+ }
+
+ if (tt != CPP_STRING)
+ {
+ error ("table name expected in odb pragma %qs", pc);
+ return;
+ }
+
+ val = TREE_STRING_POINTER (t);
+
+ if (pragma_lex (&t) != CPP_CLOSE_PAREN)
+ {
+ error ("%qs expected at the end of odb pragma %qs", ")", pc);
+ return;
+ }
+ }
+ else
+ {
+ error ("unknown odb pragma %qs", pc);
+ return;
+ }
+
+ // Record this pragma.
+ //
+ pragma prag (p, val, loc);
+
+ if (decl)
+ decl_pragmas_[decl].insert (prag);
+ else
+ {
+ tree scope (current_scope ());
+
+ if (!CLASS_TYPE_P (scope))
+ scope = global_namespace;
+
+ loc_pragmas_[scope].push_back (prag);
+ }
+
+ // See if there are any more pragmas.
+ //
+ tt = pragma_lex (&t);
+
+ if (tt == CPP_NAME)
+ {
+ handle_pragma (IDENTIFIER_POINTER (t));
+ }
+ else if (tt != CPP_EOF)
+ error ("unexpected text after %qs in odb pragma", p.c_str ());
+}
+
+extern "C" void
+handle_pragma_odb_column (cpp_reader*)
+{
+ handle_pragma ("column");
+}
+
+extern "C" void
+handle_pragma_odb_table (cpp_reader*)
+{
+ handle_pragma ("table");
+}
+
+extern "C" void
+register_odb_pragmas (void*, void*)
+{
+ c_register_pragma_with_expansion ("odb", "column", handle_pragma_odb_column);
+ c_register_pragma_with_expansion ("odb", "table", handle_pragma_odb_table);
+}
diff --git a/odb/pragma.hxx b/odb/pragma.hxx
new file mode 100644
index 0000000..1a8a98f
--- /dev/null
+++ b/odb/pragma.hxx
@@ -0,0 +1,89 @@
+// file : odb/pragma.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_PRAGMA_HXX
+#define ODB_PRAGMA_HXX
+
+#include <odb/gcc.hxx>
+
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+
+struct pragma
+{
+ pragma (std::string const& n, std::string const& v, location_t l)
+ : name (n), value (v), loc (l)
+ {
+ }
+
+ bool
+ operator< (pragma const& y) const
+ {
+ return name < y.name;
+ }
+
+ std::string name;
+ std::string value;
+ location_t loc;
+};
+
+typedef std::vector<pragma> pragma_list;
+
+// A set of pragmas. Insertion of a pragma with the same name
+// overrides the old value.
+//
+struct pragma_set: std::set<pragma>
+{
+ typedef std::set<pragma> base;
+
+ void
+ insert (pragma const& p)
+ {
+ std::pair<iterator, bool> r (base::insert (p));
+
+ if (!r.second)
+ {
+ pragma& x (const_cast<pragma&> (*r.first));
+ x = p;
+ }
+ }
+
+ template <typename I>
+ void
+ insert (I begin, I end)
+ {
+ for (; begin != end; ++begin)
+ insert (*begin);
+ }
+};
+
+
+// Position pragmas inside a class or namespace. The key for the
+// namespace case is the global_namespace node.
+//
+typedef std::map<tree, pragma_list> loc_pragmas;
+
+// Pragmas associated with this declaration.
+//
+typedef std::map<tree, pragma_set> decl_pragmas;
+
+extern loc_pragmas loc_pragmas_;
+extern decl_pragmas decl_pragmas_;
+
+extern "C" void
+register_odb_pragmas (void*, void*);
+
+// Check that the pragma is applicable to the declaration. Return true
+// on success, complain and return false otherwise.
+//
+bool
+check_decl_type (tree decl,
+ std::string const& name,
+ std::string const& prag,
+ location_t);
+
+#endif // ODB_PRAGMA_HXX