diff options
Diffstat (limited to 'odb/odb/pragma.hxx')
-rw-r--r-- | odb/odb/pragma.hxx | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/odb/odb/pragma.hxx b/odb/odb/pragma.hxx new file mode 100644 index 0000000..0d4d3f1 --- /dev/null +++ b/odb/odb/pragma.hxx @@ -0,0 +1,287 @@ +// file : odb/pragma.hxx +// license : GNU GPL v3; see accompanying LICENSE file + +#ifndef ODB_PRAGMA_HXX +#define ODB_PRAGMA_HXX + +#include <odb/gcc.hxx> + +#include <map> +#include <set> +#include <vector> +#include <string> + +#include <odb/option-types.hxx> // database + +#include <libcutl/container/any.hxx> +#include <libcutl/container/multi-index.hxx> +#include <libcutl/compiler/context.hxx> + +struct virt_declaration +{ + virt_declaration (location_t l, + location_t o, + int ob, + std::string const& n, + gcc_tree_code_type tc, + tree t) + : loc (l), ord (o), ord_bias (ob), name (n), tree_code (tc), type (t) {} + + location_t loc; + location_t ord; // Ordering location for before/after support. + int ord_bias; // Ordering bias for the same locations. + std::string name; + gcc_tree_code_type tree_code; + tree type; // Declaration's type. +}; + +// 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_set +{ + typedef cutl::container::key<std::string, gcc_tree_code_type> key; + typedef std::map<key, virt_declaration> map; + typedef cutl::container::map_const_iterator<map> const_iterator; + + std::pair<const_iterator, bool> + insert (const virt_declaration& v) + { + std::pair<map::iterator, bool> r ( + map_.insert (map::value_type (key (v.name, v.tree_code), v))); + + const_iterator i (r.first); + + if (r.second) + r.first->first.assign (i->name, i->tree_code); + + return std::make_pair (i, r.second); + } + + const_iterator + find (std::string const& name, gcc_tree_code_type tree_code) const + { + return map_.find (key (name, tree_code)); + } + + const_iterator begin () const {return map_.begin ();} + const_iterator end () const {return map_.end ();} + +private: + map map_; +}; + +// 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; + + gcc_tree_code_type + 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) (declaration const& decl, + std::string const& decl_name, + std::string const& prag_name, + location_t); + + // Add the pragma value to the context. + // + typedef void (*add_func) (cutl::compiler::context&, + std::string const& key, + cutl::container::any const& value, + location_t); + + pragma (std::string const& pn, + std::string const& cn, + cutl::container::any const& v, + location_t l, + check_func c, + add_func a) + : pragma_name (pn), + context_name (cn), + value (v), + loc (l), + check (c), + add (a) + { + } + + std::string pragma_name; // Actual pragma name for diagnostics. + std::string context_name; // Context entry name. + cutl::container::any value; + location_t loc; + check_func check; + add_func add; +}; + +typedef std::vector<pragma> pragma_list; + +// A set of pragmas. Insertion of a pragma with the same name and no +// custom add function overrides the old value. +// +struct pragma_set: std::multimap<std::string, pragma> +{ + typedef std::multimap<std::string, pragma> base; + + pragma& + insert (pragma const& p) + { + std::string const& n (p.context_name); + std::pair<iterator, iterator> r (equal_range (n)); + + iterator i (end ()); + + if (p.add == 0) + { + if (r.first != r.second) + { + i = r.first; + assert (++r.first == r.second); + + i->second = p; + } + } + else if (r.first != r.second) + assert ((--r.second)->second.loc <= p.loc); + + if (i == end ()) + i = base::insert (base::value_type (n, p)); + + return i->second; + } + + void + insert (const_iterator begin, const_iterator end) + { + for (; begin != end; ++begin) + insert (begin->second); + } + + // Return the last pragma in the equal range which (by construction) has the + // location greater or equal to all the other pragmas in this range. + // + iterator + find (std::string const& n) + { + return equal_range (n).second; + } +}; + + +// 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; +extern loc_pragmas loc_pragmas_; + +// Position pragmas for namespaces. Because re-opened namespaces do +// not have any representation in the GCC tree, these are handled in +// a special way. They are stored as a list of pragmas and their outer +// namespaces. +// +struct ns_loc_pragma +{ + typedef ::pragma pragma_type; + ns_loc_pragma (tree n, pragma_type const& p): ns (n), pragma (p) {} + + tree ns; + pragma_type pragma; +}; + +typedef std::vector<ns_loc_pragma> ns_loc_pragmas; +extern ns_loc_pragmas ns_loc_pragmas_; + +// Pragmas associated with specific declarations (real or virtual). +// +typedef std::map<declaration, pragma_set> decl_pragmas; +extern decl_pragmas decl_pragmas_; + +// Database we are generating code for as well as multi-database support. +// Used to ignore database-specific pragmas. +// +extern database pragma_db_; +extern multi_database pragma_multi_; + +extern "C" void +register_odb_pragmas (void*, void*); + +struct pragmas_failed {}; + +void +post_process_pragmas (); + +#endif // ODB_PRAGMA_HXX |