diff options
Diffstat (limited to 'odb/parser.cxx')
-rw-r--r-- | odb/parser.cxx | 2323 |
1 files changed, 0 insertions, 2323 deletions
diff --git a/odb/parser.cxx b/odb/parser.cxx deleted file mode 100644 index 58388c9..0000000 --- a/odb/parser.cxx +++ /dev/null @@ -1,2323 +0,0 @@ -// file : odb/parser.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include <odb/gcc.hxx> // Keep it first. - -#include <set> -#include <map> -#include <vector> -#include <string> -#include <cassert> -#include <sstream> -#include <iostream> - -#include <odb/diagnostics.hxx> -#include <odb/parser.hxx> -#include <odb/semantics.hxx> - -using namespace std; -using namespace semantics; - -class parser::impl -{ -public: - typedef parser::failed failed; - - impl (options const&, loc_pragmas&, ns_loc_pragmas&, decl_pragmas&); - - unique_ptr<unit> - parse (tree global_scope, path const& main_file); - -private: - typedef semantics::access access; - - // Extended GCC 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), 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; - }; - - typedef multiset<tree_decl> decl_set; - -private: - void - collect (tree ns); - - void - emit (); - - // 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. - // - type* - emit_type_decl (tree); - - // Emit a template declaration. - // - void - emit_template_decl (tree); - - class_template& - emit_class_template (tree, bool stub = false); - - union_template& - emit_union_template (tree, bool stub = false); - - template <typename T> - T& - emit_class (tree, path const& f, size_t l, size_t c, bool stub = false); - - template <typename T> - T& - emit_union (tree, path const& f, size_t l, size_t c, bool stub = false); - - // Access is not used when creating a stub. - // - enum_& - emit_enum (tree, - access, - path const& f, - size_t l, - size_t c, - bool stub = false); - - // Create new or find existing semantic graph type. - // - type& - emit_type (tree, access, path const& f, size_t l, size_t c); - - type& - create_type (tree, access, path const& f, size_t l, size_t c); - - string - emit_type_name (tree, bool direct = true); - - - // - // Pragma handling. - // - void - add_pragma (node&, pragma const&); - - // Process positioned and named pragmas. - // - void - process_pragmas (declaration const&, - node&, - string const& name, - decl_set::const_iterator begin, - decl_set::const_iterator cur, - decl_set::const_iterator end); - - // Process named pragmas only. - // - void - process_named_pragmas (declaration const&, node&); - - void - diagnose_unassoc_pragmas (decl_set const&); - - // Return declaration's fully-qualified scope name (e.g., ::foo::bar). - // - string - fq_scope (tree); - - // Return declaration's access. - // - access - decl_access (tree decl) - { - // Note that TREE_PUBLIC() returns something other than what we need. - // - if (TREE_PRIVATE (decl)) - return access::private_; - - if (TREE_PROTECTED (decl)) - return access::protected_; - - return access::public_; - } - - // - // - template <typename T> - void - define_fund (tree); - -private: - options const& ops_; - loc_pragmas& loc_pragmas_; - ns_loc_pragmas& ns_loc_pragmas_; - decl_pragmas& decl_pragmas_; - - bool trace; - ostream& ts; - - unit* unit_; - scope* scope_; - size_t error_; - - decl_set decls_; - - typedef map<location_t, tree> decl_map; - decl_map all_decls_; -}; - -bool parser::impl::tree_decl:: -operator< (tree_decl const& y) const -{ - location_t xl, yl; - int xb (0), yb (0); - - if (decl != 0) - xl = real_source_location (decl); - else if (vdecl != 0) - { - xl = vdecl->ord; - xb = vdecl->ord_bias; - } - else - xl = prag->loc; - - if (y.decl != 0) - yl = real_source_location (y.decl); - else if (y.vdecl != 0) - { - yl = y.vdecl->ord; - yb = y.vdecl->ord_bias; - } - else - yl = y.prag->loc; - - // If both are virtual and at the same location, use the definition - // location to order them. - // - if (vdecl != 0 && y.vdecl != 0 && xl == yl && xb == yb) - { - xl = vdecl->loc; - yl = y.vdecl->loc; - } - - return xl < yl || (xl == yl && xb < yb); -} - -// -// Function templates. -// - -template <typename T> -void parser::impl:: -define_fund (tree t) -{ - t = TYPE_MAIN_VARIANT (t); - char const* name (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)))); - - T& node (unit_->new_fund_node<T> (t)); - unit_->new_edge<defines> (*scope_, node, name); - unit_->insert (t, node); - - process_named_pragmas (t, node); -} - -template <typename T> -T& parser::impl:: -emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub) -{ - c = TYPE_MAIN_VARIANT (c); - - // See if there is a stub already for this type. - // - T* c_node (0); - - if (node* n = unit_->find (c)) - { - c_node = &dynamic_cast<T&> (*n); - } - else - { - c_node = &unit_->new_node<T> (file, line, clmn, c); - unit_->insert (c, *c_node); - } - - if (stub || !COMPLETE_TYPE_P (c)) - return *c_node; - - // Traverse base information. - // - tree bis (TYPE_BINFO (c)); - size_t n (bis ? BINFO_N_BASE_BINFOS (bis) : 0); - - for (size_t i (0); i < n; i++) - { - tree bi (BINFO_BASE_BINFO (bis, i)); - access a (access::public_); - - if (BINFO_BASE_ACCESSES (bis)) - { - tree ac (BINFO_BASE_ACCESS (bis, i)); - - if (ac == NULL_TREE || ac == access_public_node) - { - a = access::public_; - } - else if (ac == access_protected_node) - { - a = access::protected_; - } - else - { - assert (ac == access_private_node); - a = access::private_; - } - } - - bool virt (BINFO_VIRTUAL_P (bi)); - tree base (TYPE_MAIN_VARIANT (BINFO_TYPE (bi))); - - // 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); - - if (trace) - name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (base))); - } - else - { - // Use public access for a template instantiation in the inheritance - // declaration. - // - b_node = &dynamic_cast<class_&> ( - emit_type (base, access::public_, file, line, clmn)); - - if (trace) - name = emit_type_name (base); - } - - unit_->new_edge<inherits> (*c_node, *b_node, a, virt); - - if (trace) - ts << "\t" << a.string () << (virt ? " virtual" : "") << " base " - << name << " (" << static_cast<type*> (b_node) << ")" << endl; - } - - // Collect member declarations so that we can traverse them in - // the source code order. - // - decl_set decls; - - for (tree d (TYPE_FIELDS (c)); 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: - { - break; - } - } - } - - // 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. - // - { - 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 b (decls.begin ()), i (b), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - 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 (real_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)) - { - case TYPE_DECL: - { - 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: - { - emit_template_decl (d); - break; - } - case FIELD_DECL: - { - // If this is a bit-field then TREE_TYPE may be a modified type - // with lesser precision. In this case, DECL_BIT_FIELD_TYPE - // will be the type that was original specified. Use that type - // for now. Furthermore, bitfields can be anonymous, which we - // ignore. - // - // - bool bf (DECL_C_BIT_FIELD (d)); - - if (bf && DECL_NAME (d) == 0) - break; - - // Another case where we can have NULL name is anonymous struct - // or union extension, for example: - // - // struct s - // { - // union - // { - // int a; - // int b; - // }; - // }; - // - // GCC appears to create a fake member for such a struct/union - // without any name. Ignore such members for now. - // - if (DECL_NAME (d) == 0) - break; - - tree t (bf ? DECL_BIT_FIELD_TYPE (d) : 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)); - - access a (decl_access (d)); - - type& type_node (emit_type (t, a, file, line, clmn)); - data_member& member_node ( - unit_->new_node<data_member> (file, line, clmn, d)); - unit_->insert (d, member_node); - - unit_->new_edge<names> (*c_node, member_node, 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 (t)) - edge.hint (*hint); - - if (trace) - { - string type_name (emit_type_name (t)); - - ts << "\t" << a.string () << " data member " << type_name - << " (" << &type_node << ") " << name << " at " - << file << ":" << line << endl; - } - - // Process pragmas that may be associated with this field. - // - process_pragmas (d, member_node, name, b, i, e); - - break; - } - default: - { - assert (false); - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *c_node; -} - -template <typename T> -T& parser::impl:: -emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub) -{ - 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, u); - 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: - { - break; - } - } - } - - // 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 b (decls.begin ()), i (b), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TYPE_DECL: - { - 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: - { - emit_template_decl (d); - break; - } - case FIELD_DECL: - { - // We can have NULL name in case of anonymous struct or union - // extension, for example: - // - // union s - // { - // struct - // { - // int a; - // int b; - // }; - // int c; - // }; - // - // GCC appears to create a fake member for such a struct/union - // without any name. Ignore such members for now. - // - if (DECL_NAME (d) == 0) - break; - - 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)); - - access a (decl_access (d)); - - type& type_node (emit_type (t, a, file, line, clmn)); - data_member& member_node ( - unit_->new_node<data_member> (file, line, clmn, d)); - unit_->insert (d, member_node); - - unit_->new_edge<names> (*u_node, member_node, 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 (t)) - edge.hint (*hint); - - if (trace) - { - string type_name (emit_type_name (t)); - - ts << "\t" << a.string () << " union member " << type_name - << " (" << &type_node << ") " << name << " at " - << file << ":" << line << endl; - } - - // Process pragmas that may be associated with this field. - // - process_pragmas (d, member_node, name, b, i, e); - - break; - } - default: - { - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *u_node; -} - -// -// Functions. -// - -parser::impl:: -impl (options const& ops, - loc_pragmas & lp, - ns_loc_pragmas& nslp, - decl_pragmas& dp) - : ops_ (ops), - loc_pragmas_ (lp), - ns_loc_pragmas_ (nslp), - decl_pragmas_ (dp), - trace (ops.trace ()), - ts (cerr) -{ -} - -unique_ptr<unit> parser::impl:: -parse (tree global_scope, path const& main_file) -{ - unique_ptr<unit> u (new unit (main_file)); - u->insert (global_namespace, *u); - process_named_pragmas (global_namespace, *u); - - unit_ = u.get (); - scope_ = unit_; - error_ = 0; - - // Define fundamental types. - // - define_fund<fund_void> (void_type_node); - 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); - define_fund<fund_unsigned_short> (short_unsigned_type_node); - define_fund<fund_int> (integer_type_node); - define_fund<fund_unsigned_int> (unsigned_type_node); - define_fund<fund_long> (long_integer_type_node); - define_fund<fund_unsigned_long> (long_unsigned_type_node); - define_fund<fund_long_long> (long_long_integer_type_node); - define_fund<fund_unsigned_long_long> (long_long_unsigned_type_node); - define_fund<fund_float> (float_type_node); - define_fund<fund_double> (double_type_node); - define_fund<fund_long_double> (long_double_type_node); - - // First collect all the namespace-level declarations we are - // interested in in the line-decl map so that they appear in - // the source code order. - // - collect (global_scope); - - // Add namespace-level position 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 ()); - } - - // Convert position namespace pragmas to name pragmas. - // - for (ns_loc_pragmas::const_iterator i (ns_loc_pragmas_.begin ()); - i != ns_loc_pragmas_.end (); ++i) - { - pragma const& p (i->pragma); - - decl_map::const_iterator j (all_decls_.lower_bound (p.loc)); - - if (j == all_decls_.end ()) - { - error (p.loc) - << "db pragma '" << p.pragma_name << "' is not associated with a " - << "namespace declaration" << endl; - error_++; - continue; - } - - // Find the "namespace difference" between this declaration and - // the pragma's namespace. The outermost namespace in the result - // is what we are looking for. - // - tree ns (0); - - for (tree prev (j->second), scope (CP_DECL_CONTEXT (prev));; - scope = CP_DECL_CONTEXT (scope)) - { - if (scope == i->ns) - { - ns = prev; - break; - } - - if (scope == global_namespace) - break; - - prev = scope; - } - - if (ns == 0 || TREE_CODE (ns) != NAMESPACE_DECL) - { - error (p.loc) - << "db pragma '" << p.pragma_name << "' is not associated with a " - << "namespace declaration" << endl; - error_++; - continue; - } - - pragma_set& s (decl_pragmas_[ns]); - pragma_set::iterator it (s.find (p.context_name)); - - // Make sure we override only if this pragma came after the one - // already in the set. - // - if (it == s.end () || it->second.loc <= p.loc) - s.insert (p); - } - - // Construct the semantic graph. - // - if (error_ == 0) - emit (); - - if (error_ > 0) - throw failed (); - - return u; -} - -void parser::impl:: -collect (tree ns) -{ - cp_binding_level* level = NAMESPACE_LEVEL (ns); - tree decl = level->names; - - // Collect declarations. - // - for (; decl != NULL_TREE; decl = TREE_CHAIN (decl)) - { - all_decls_[real_source_location (decl)] = decl; - - if (DECL_IS_BUILTIN (decl)) - continue; - - switch (TREE_CODE (decl)) - { - case TYPE_DECL: - { - // Skip special type declarations. - // - if (DECL_NAME (decl) == NULL_TREE) - continue; - - tree type (TREE_TYPE (decl)); - if (LAMBDA_TYPE_P (type)) - continue; - - decls_.insert (decl); - break; - } - case TEMPLATE_DECL: - { - if (DECL_CLASS_TEMPLATE_P (decl)) - decls_.insert (decl); - - break; - } - default: - { - break; - } - } - } - - // Traverse namespaces. - // - for ( -#if BUILDING_GCC_MAJOR >= 8 - decl = level->names; -#else - decl = level->namespaces; -#endif - decl != NULL_TREE; - decl = TREE_CHAIN (decl)) - { -#if BUILDING_GCC_MAJOR >= 8 - // Now namespaces are interleaved with other declarations. In fact, we - // could probably collect everything in a single pass. - // - if (TREE_CODE (decl) != NAMESPACE_DECL) - continue; -#endif - - // Ignore namespace aliases. - // - if (DECL_NAMESPACE_ALIAS (decl)) - continue; - - if (!DECL_IS_BUILTIN (decl) || DECL_NAMESPACE_STD_P (decl)) - { - if (trace) - { - tree dn (DECL_NAME (decl)); - char const* name (dn ? IDENTIFIER_POINTER (dn) : "<anonymous>"); - - ts << "namespace " << name << " at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - } - - collect (decl); - } - } -} - -void parser::impl:: -emit () -{ - for (decl_set::const_iterator b (decls_.begin ()), i (b), - e (decls_.end ()); i != e; ++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. - // - string pfx; - string ns (fq_scope (decl)); - - for (pfx = scope_->fq_name (); !pfx.empty (); pfx = scope_->fq_name ()) - { - size_t n (pfx.size ()); - - // Make sure we handle cases like ns="::foobar", pfx="::foo". - // - if (ns.compare (0, n, pfx) == 0 && (ns.size () == n || ns[n - 1] == ':')) - break; - - if (trace) - ts << "closing namespace " << scope_->name () << endl; - - scope_ = &scope_->scope_ (); - } - - // Build the rest of the namespace hierarchy for this declaration. - // - if (ns != pfx) - { - path f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - for (size_t b (pfx.size () + 2), e (ns.find ("::", b)); - b != string::npos;) - { - string n (ns, b, e == string::npos ? e : e - b); - - if (trace) - ts << "opening namespace " << n << " for " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - // Use the declarations's file, line, and column as an - // approximation for this namespace origin. Also resolve - // the tree node for this namespace. - // -#if BUILDING_GCC_MAJOR >= 8 - tree tree_node ( - get_namespace_binding ( - scope_->tree_node (), get_identifier (n.c_str ()))); -#else - tree tree_node ( - namespace_binding ( - get_identifier (n.c_str ()), scope_->tree_node ())); -#endif - - namespace_& node (unit_->new_node<namespace_> (f, l, c, tree_node)); - unit_->new_edge<defines> (*scope_, node, n); - - if (namespace_* orig = - dynamic_cast<namespace_*> (unit_->find (tree_node))) - { - // This is an extension. - // - node.original (*orig); - } - else - { - // This is the original. Add it to the map and process any - // pragmas it might have (at this stage namespaces can only - // have name pragmas). - // - unit_->insert (tree_node, node); - process_named_pragmas (tree_node, node); - } - - scope_ = &node; - - if (e == string::npos) - b = e; - else - { - b = e + 2; - e = ns.find ("::", b); - } - } - } - - switch (TREE_CODE (decl)) - { - case TYPE_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: - { - emit_template_decl (decl); - break; - } - default: - { - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls_); -} - -type* parser::impl:: -emit_type_decl (tree decl) -{ - tree t (TREE_TYPE (decl)); - gcc_tree_code_type tc (TREE_CODE (t)); - - tree decl_name (DECL_NAME (decl)); - char const* name (IDENTIFIER_POINTER (decl_name)); - - 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 - // says that in typedef struct {} S; S becomes struct's - // name. - // - if (IDENTIFIER_ANON_P (decl_name)) - { - tree d (TYPE_NAME (t)); - - if (d != NULL_TREE && - !DECL_ARTIFICIAL (d) && - DECL_NAME (d) != NULL_TREE && - !IDENTIFIER_ANON_P (DECL_NAME (d))) - { - decl = d; - decl_name = DECL_NAME (decl); - name = IDENTIFIER_POINTER (decl_name); - } - else - { - // This type has only the synthesized name which means that - // it is either typedef'ed as a derived type or it is used - // to declare a varibale or similar. The first case will be - // covered by the typedef handling code below. The second - // case will be covere by emit_type(). - // - return 0; - } - } - - path file (DECL_SOURCE_FILE (decl)); - size_t line (DECL_SOURCE_LINE (decl)); - size_t clmn (DECL_SOURCE_COLUMN (decl)); - - type* node (0); - - // Pointers to member functions are represented as record - // types. Detect and handle this case. - // - if (TYPE_PTRMEMFUNC_P (t)) - { - t = TYPE_MAIN_VARIANT (t); - node = &unit_->new_node<unsupported_type> ( - file, line, clmn, t, "pointer_to_member_function_type"); - unit_->insert (t, *node); - } - else - { - - if (trace) - ts << "start " << gcc_tree_code_name(tc) << " " << name - << " at " << file << ":" << line << endl; - - 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, decl_access (decl), file, line, clmn); - break; - } - default: - break; - } - - if (trace) - ts << "end " << gcc_tree_code_name(tc) << " " << name - << " (" << node << ") at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - } - - if (COMPLETE_TYPE_P (t)) - unit_->new_edge<defines> (*scope_, *node, name); - else - unit_->new_edge<declares> (*scope_, *node, name); - - return node; - } - else - { - // Normal typedef. We need to detect and ignore the anonymous - // class typedef case described above since we already used - // this name to define the class. - // - if ((tc == RECORD_TYPE || tc == UNION_TYPE || tc == ENUMERAL_TYPE) && - TYPE_NAME (TYPE_MAIN_VARIANT (t)) == decl) - return 0; - - path f (DECL_SOURCE_FILE (decl)); - size_t l (DECL_SOURCE_LINE (decl)); - size_t c (DECL_SOURCE_COLUMN (decl)); - - type& node (emit_type (t, decl_access (decl), f, l, c)); - typedefs& edge (unit_->new_edge<typedefs> (*scope_, node, name)); - - // Find our hint. - // - if (tree ot = DECL_ORIGINAL_TYPE (decl)) - { - if (names* hint = unit_->find_hint (ot)) - edge.hint (*hint); - } - - // Add this edge to the hint map. It may already be there if we - // are handling something like this: - // - // typedef foo bar; - // typedef bar foo; - // - // GCC also appears to re-purpose a node for another name (not - // sure if its a bug or a feature), so use the latest seen name. - // - unit_->insert_hint (t, edge); - - if (trace) - { - string s (emit_type_name (t, false)); - - ts << "typedef " << s << " (" << &node << ") -> " << name - << " at " << f << ":" << l << endl; - } - - return 0; - } -} - -void parser::impl:: -emit_template_decl (tree decl) -{ - // Currently we only handle class/union templates. - // - tree t (TREE_TYPE (DECL_TEMPLATE_RESULT (decl))); - gcc_tree_code_type tc (TREE_CODE (t)); - - if (trace) - { - ts << gcc_tree_code_name(tc) << " template (" << decl << ") " - << IDENTIFIER_POINTER (DECL_NAME (decl)) << " (" << t << ") at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - ts << "specializations:" << endl; - - for (tree s (DECL_TEMPLATE_SPECIALIZATIONS (decl)); - s != NULL_TREE; s = TREE_CHAIN (s)) - { - tree t (TREE_TYPE (s)); - tree d (TYPE_NAME (t)); - - ts << "\tspecialization " << t << " at " - << DECL_SOURCE_FILE (d) << ":" - << DECL_SOURCE_LINE (d) << endl; - } - - ts << "instantiations:" << endl; - - for (tree i (DECL_TEMPLATE_INSTANTIATIONS (decl)); - i != NULL_TREE; i = TREE_CHAIN (i)) - { - tree t (TREE_VALUE (i)); - tree d (TYPE_NAME (t)); - - ts << "\tinstantiation " << t << " at " - << DECL_SOURCE_FILE (d) << ":" - << DECL_SOURCE_LINE (d) << endl; - } - } - - char const* name (IDENTIFIER_POINTER (DECL_NAME (decl))); - - if (trace) - ts << "start " << gcc_tree_code_name(tc) << " template " << name << " at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; - - 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); - - if (trace) - ts << "end " << gcc_tree_code_name(tc) << " template " << name - << " (" << t_node << ") at " - << DECL_SOURCE_FILE (decl) << ":" - << DECL_SOURCE_LINE (decl) << endl; -} - -class_template& parser::impl:: -emit_class_template (tree t, bool stub) -{ - // See if there is a stub already for this template. - // - class_template* ct_node (0); - tree c (TREE_TYPE (DECL_TEMPLATE_RESULT (t))); - - if (node* n = unit_->find (t)) - { - ct_node = &dynamic_cast<class_template&> (*n); - } - else - { - path f (DECL_SOURCE_FILE (t)); - size_t ln (DECL_SOURCE_LINE (t)); - size_t cl (DECL_SOURCE_COLUMN (t)); - - ct_node = &unit_->new_node<class_template> (f, ln, cl, c); - unit_->insert (t, *ct_node); - } - - 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; - } - default: - { - break; - } - } - } - - scope* prev_scope (scope_); - scope_ = ct_node; - - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TEMPLATE_DECL: - { - emit_template_decl (d); - break; - } - default: - { - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *ct_node; -} - -union_template& parser::impl:: -emit_union_template (tree t, bool stub) -{ - // See if there is a stub already for this template. - // - union_template* ut_node (0); - tree u (TREE_TYPE (DECL_TEMPLATE_RESULT (t))); - - 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, u); - unit_->insert (t, *ut_node); - } - - 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; - } - default: - { - break; - } - } - } - - scope* prev_scope (scope_); - scope_ = ut_node; - - for (decl_set::const_iterator i (decls.begin ()), e (decls.end ()); - i != e; ++i) - { - // Skip pragmas. - // - if (i->prag) - continue; - - tree d (i->decl); - - switch (TREE_CODE (d)) - { - case TEMPLATE_DECL: - { - emit_template_decl (d); - break; - } - default: - { - break; - } - } - } - - // Diagnose any position pragmas that haven't been associated. - // - diagnose_unassoc_pragmas (decls); - - scope_ = prev_scope; - return *ut_node; -} - -enum_& parser::impl:: -emit_enum (tree e, - access access, - path const& file, - size_t line, - size_t clmn, - bool stub) -{ - 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, e); - - // Set the underlying type even for incomplete (forward-declared) enums. - // - tree ut (ENUM_UNDERLYING_TYPE (e)); - names* hint (unit_->find_hint (ut)); - integral_type* un = dynamic_cast<integral_type*> ( - unit_->find (TYPE_MAIN_VARIANT (ut))); - - // For "old" enums GCC creates a distinct type node and the only way to - // get to one of the known integrals is via its name. - // - if (un == 0) - { - ut = TREE_TYPE (TYPE_NAME (ut)); - un = dynamic_cast<integral_type*> (unit_->find (TYPE_MAIN_VARIANT (ut))); - } - - underlies& edge (unit_->new_edge<underlies> (*un, *e_node)); - - if (hint != 0) - edge.hint (*hint); - - 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))); - tree decl (TREE_VALUE (er)); - tree tval (DECL_INITIAL (decl)); - - unsigned long long val (integer_value (tval)); - - // 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, er, val); - unit_->new_edge<enumerates> (*e_node, er_node); - unit_->insert (decl, er_node); - - // In C++11 the enumerators are always available in the enum's - // scope, even for old enums. - // - if (ops_.std () >= cxx_version::cxx11) - unit_->new_edge<names> (*e_node, er_node, name, access::public_); - - // Inject enumerators into the outer scope unless this is an - // enum class. - // - if (UNSCOPED_ENUM_P (e)) - unit_->new_edge<names> (*scope_, er_node, name, access); - - if (trace) - ts << "\tenumerator " << name << " at " << file << ":" << line << endl; - } - - return *e_node; -} - -type& parser::impl:: -emit_type (tree t, - access access, - path const& file, - size_t line, - size_t clmn) -{ - tree mv (TYPE_MAIN_VARIANT (t)); - - if (trace) - { - ts << gcc_tree_code_name(TREE_CODE (t)) << " " << t - << " main " << mv << endl; - - for (tree v (TYPE_MAIN_VARIANT (t)); v != 0; v = TYPE_NEXT_VARIANT (v)) - ts << "\tvariant " << v << " " << CP_TYPE_CONST_P (v) << endl; - } - - node* n (unit_->find (mv)); - - type& r (n != 0 - ? dynamic_cast<type&> (*n) - : create_type (t, access, file, line, clmn)); - - if (trace && n != 0) - ts << "found node " << &r << " for type " << mv << endl; - - if (cp_type_quals (t) == TYPE_UNQUALIFIED) - { - unit_->insert (t, r); // Add this variant to the map. - return r; - } - - // See if this type already has this variant. - // - bool qc (CP_TYPE_CONST_P (t)); - bool qv (CP_TYPE_VOLATILE_P (t)); - bool qr (CP_TYPE_RESTRICT_P (t)); - - for (type::qualified_iterator i (r.qualified_begin ()); - i != r.qualified_end (); ++i) - { - qualifier& q (i->qualifier ()); - - if (q.const_ () == qc && q.volatile_ () == qv && q.restrict_ () == qr) - { - if (trace) - ts << "found qualifier variant " << &q << endl; - - unit_->insert (t, q); // Add this variant to the map. - return q; - } - } - - // No such variant yet. Create a new one. Qualified types are not - // unique in the tree so don't add this node to the map. - // - qualifier& q (unit_->new_node<qualifier> (file, line, clmn, t, qc, qv, qr)); - qualifies& e (unit_->new_edge<qualifies> (q, r)); - unit_->insert (t, q); - - // See if there is a name hint for this type. - // - // If TREE_TYPE (TYPE_NAME (t)) != t then we have an inline qualifier, - // as in: - // - // const foo x; - // - // If they are equal, then there are two possible cases. The first is - // when we have a qualifier typedef, as in: - // - // typedef const foo cfoo; - // cfoo x; - // - // The second is when we have a qualifier typedef but what is actually - // used in the declaration is an inline qualifier, as in: - // - // typedef const foo cfoo; - // const foo x; - // - // Unfortunately, in GCC, these two cases are indistinguishable. In - // certain cases this can lead to a wrong hint being used for the base - // type, for example: - // - // typedef foo my_foo; - // typedef foo foo_t; - // typedef const foo_t cfoo; - // - // const my_foo x; - // - // Above, the hint will be foo_t while it should be my_foo. - // - tree bt (0); - - if (tree decl = TYPE_NAME (t)) - { - bt = TREE_TYPE (decl); - - if (t == bt) - { - // A const type can be named only with a typedef. Get the - // original type. - // - tree ot (DECL_ORIGINAL_TYPE (decl)); - - // And chase it one more time to get rid of the qualification. - // - decl = TYPE_NAME (ot); - bt = decl != 0 ? TREE_TYPE (decl) : 0; - } - } - - if (bt != 0) - { - if (names* hint = unit_->find_hint (bt)) - e.hint (*hint); - } - - process_named_pragmas (t, q); - - return q; -} - -type& parser::impl:: -create_type (tree t, - access access, - path const& file, - size_t line, - size_t clmn) -{ - type* r (0); - gcc_tree_code_type tc (TREE_CODE (t)); - - switch (tc) - { - // - // User-defined types. - // - case RECORD_TYPE: - case UNION_TYPE: - { - t = TYPE_MAIN_VARIANT (t); - tree ti (TYPE_TEMPLATE_INFO (t)); - - if (ti == NULL_TREE) - { - // Ordinary class. There are two situations which can lead - // here. First is when we have an anonymous class that is - // part of the declaration, for example: - // - // typedef const struct {...} s; - // - // The second situation is a named class definition which - // we haven't parsed yet. In this case we are going to - // create a "stub" class node which will be processed and - // filled in later. - // - - // Pointers to member functions are represented as record - // types. Detect and handle this case. - // - if (TYPE_PTRMEMFUNC_P (t)) - { - r = &unit_->new_node<unsupported_type> ( - file, line, clmn, t, "pointer_to_member_function_type"); - unit_->insert (t, *r); - } - else - { - tree d (TYPE_NAME (t)); - - if (trace) - ts << "start anon/stub " << gcc_tree_code_name(tc) << " at " - << file << ":" << line << endl; - - if (d == NULL_TREE || IDENTIFIER_ANON_P (DECL_NAME (d))) - { - 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. - // - 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); - } - - if (trace) - ts << "end anon/stub " << gcc_tree_code_name(tc) << " (" << r << ")" - << " at " << file << ":" << line << endl; - } - } - else - { - // Template instantiation. - // - tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - - // Get to the most general template declaration. - // - while (DECL_TEMPLATE_INFO (decl)) - decl = DECL_TI_TEMPLATE (decl); - - type_template* t_node (0); - - // 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 - { - if (trace) - ts << "start stub " << gcc_tree_code_name(tc) << " template for (" - << decl << ") at " << file << ":" << line << endl; - - if (tc == RECORD_TYPE) - t_node = &emit_class_template (decl, true); - else - t_node = &emit_union_template (decl, true); - - if (trace) - ts << "end stub " << gcc_tree_code_name(tc) << " template (" - << t_node << ") at " << file << ":" << line << endl; - } - - if (trace) - ts << "start " << gcc_tree_code_name(tc) << " instantiation (" - << t << ") for template (" << t_node << ")" - << " at " << file << ":" << line << endl; - - type_instantiation* i_node (0); - - 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); - - if (trace) - ts << "end " << gcc_tree_code_name(tc) << " instantiation (" - << static_cast<type*> (i_node) << ")" - << " at " << file << ":" << line << endl; - - unit_->new_edge<instantiates> (*i_node, *t_node); - process_named_pragmas (t, *i_node); - r = i_node; - } - - 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)); - - if (trace) - ts << "start anon/stub " << gcc_tree_code_name(tc) << " at " - << file << ":" << line << endl; - - if (d == NULL_TREE || IDENTIFIER_ANON_P (DECL_NAME (d))) - { - r = &emit_enum (t, access, 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, access, f, l, c, true); - } - - if (trace) - ts << "end anon/stub " << gcc_tree_code_name(tc) << " (" << r << ")" - << " at " << file << ":" << line << endl; - - break; - } - - // - // Derived types. - // - - case ARRAY_TYPE: - { - unsigned long long size (0); - - if (tree index = TYPE_DOMAIN (t)) - { - tree max (TYPE_MAX_VALUE (index)); - - if (TREE_CODE (max) == INTEGER_CST) - { - size = integer_value (max); - - // The docs say that TYPE_DOMAIN will be NULL if the - // array doesn't specify bounds. In reality, it is - // set to ~0. - // - if (size == ~(unsigned long long) (0)) - size = 0; - - size++; // Convert max index to size. - } - else - { - error (file, line, clmn) - << "non-integer array index " << - gcc_tree_code_name(TREE_CODE (max)) << endl; - - throw failed (); - } - } - - // In GCC tree a const array has both the array type itself and the - // element type marked as const. This doesn't bode well with our - // semantic graph model where we have a separate type node for - // qualifiers. To fix this, we are going to strip the const - // qualification from the element type and only preserve it in - // the array type. In other words, we view it as "constant array" - // rather than "array of constant elements". - // - using semantics::array; // vs std::array. - - tree bt (TREE_TYPE (t)); - tree bt_mv (TYPE_MAIN_VARIANT (bt)); - type& bt_node (emit_type (bt_mv, access::public_, file, line, clmn)); - t = TYPE_MAIN_VARIANT (t); - array& a (unit_->new_node<array> (file, line, clmn, t, size)); - unit_->insert (t, a); - contains& edge (unit_->new_edge<contains> (a, bt_node)); - - // See if there is a name hint for the base type. - // - if (names* hint = unit_->find_hint ( - cp_type_quals (bt) == TYPE_UNQUALIFIED ? bt : bt_mv)) - edge.hint (*hint); - - process_named_pragmas (t, a); - r = &a; - break; - } - case REFERENCE_TYPE: - { - tree bt (TREE_TYPE (t)); - type& bt_node (emit_type (bt, access::public_, file, line, clmn)); - t = TYPE_MAIN_VARIANT (t); - reference& ref (unit_->new_node<reference> (file, line, clmn, t)); - unit_->insert (t, ref); - references& edge (unit_->new_edge<references> (ref, bt_node)); - - // See if there is a name hint for the base type. - // - if (names* hint = unit_->find_hint (bt)) - edge.hint (*hint); - - process_named_pragmas (t, ref); - r = &ref; - break; - } - case POINTER_TYPE: - { - if (!TYPE_PTRMEM_P (t)) - { - tree bt (TREE_TYPE (t)); - type& bt_node (emit_type (bt, access::public_, file, line, clmn)); - t = TYPE_MAIN_VARIANT (t); - pointer& p (unit_->new_node<pointer> (file, line, clmn, t)); - unit_->insert (t, p); - points& edge (unit_->new_edge<points> (p, bt_node)); - - // See if there is a name hint for the base type. - // - if (names* hint = unit_->find_hint (bt)) - edge.hint (*hint); - - process_named_pragmas (t, p); - r = &p; - } - else - { - t = TYPE_MAIN_VARIANT (t); - r = &unit_->new_node<unsupported_type> ( - file, line, clmn, t, "pointer_to_data_member_type"); - unit_->insert (t, *r); - - if (trace) - ts << "unsupported pointer_to_data_member_type (" << r << ")" - << " at " << file << ":" << line << endl; - } - break; - } - default: - { - t = TYPE_MAIN_VARIANT (t); - r = &unit_->new_node<unsupported_type> ( - file, line, clmn, t, gcc_tree_code_name(tc)); - unit_->insert (t, *r); - - if (trace) - ts << "unsupported " << gcc_tree_code_name(tc) << " (" << r << ")" - << " at " << file << ":" << line << endl; - - break; - } - } - - return *r; -} - -string parser::impl:: -emit_type_name (tree type, bool direct) -{ - // First see if there is a "direct" name for this type. - // - if (direct) - { - if (tree decl = TYPE_NAME (type)) - { - tree t (TREE_TYPE (decl)); - - if (t != 0 && same_type_p (type, t)) - return IDENTIFIER_POINTER (DECL_NAME (decl)); - } - } - - string r; - - if (CP_TYPE_CONST_P (type)) - r += " const"; - - if (CP_TYPE_VOLATILE_P (type)) - r += " volatile"; - - if (CP_TYPE_RESTRICT_P (type)) - r += " __restrict"; - - gcc_tree_code_type tc (TREE_CODE (type)); - - switch (tc) - { - // - // User-defined types. - // - - case RECORD_TYPE: - case UNION_TYPE: - { - tree ti (TYPE_TEMPLATE_INFO (type)); - - if (ti == NULL_TREE) - { - // Ordinary class. - // - type = TYPE_MAIN_VARIANT (type); - - // Pointers to member functions are represented as record - // types and don't have names, not even the synthesized ones. - // - if (TYPE_PTRMEMFUNC_P (type)) - r = "<pointer-to-member-function>" + r; - else - { - tree name (TYPE_NAME (type)); - r = IDENTIFIER_POINTER (DECL_NAME (name)) + r; - } - } - else - { - // Template instantiation. - // - tree decl (TI_TEMPLATE (ti)); // DECL_TEMPLATE - string id (IDENTIFIER_POINTER (DECL_NAME (decl))); - - id += '<'; - - tree args (INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti))); - - for (size_t i (0), n (TREE_VEC_LENGTH (args)); i < n ; ++i) - { - tree a (TREE_VEC_ELT (args, i)); - - if (i != 0) - id += ", "; - - // Assume type-only arguments. - // - id += emit_type_name (a); - } - - id += '>'; - - r = id + r; - } - - break; - } - - case ENUMERAL_TYPE: - { - type = TYPE_MAIN_VARIANT (type); - tree decl (TYPE_NAME (type)); - r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r; - break; - } - - // - // Derived types. - // - - case ARRAY_TYPE: - { - unsigned long long size (0); - - if (tree index = TYPE_DOMAIN (type)) - { - tree max (TYPE_MAX_VALUE (index)); - - if (TREE_CODE (max) == INTEGER_CST) - { - size = integer_value (max); - - // Same as above. - // - if (size == ~(unsigned long long) (0)) - size = 0; - - size++; - } - else - { - // Non-integer array index which we do not support. The - // error has been/will be issued in emit_type. - // - } - } - - tree t (TREE_TYPE (type)); - - if (size != 0) - { - ostringstream ostr; - ostr << size; - r = emit_type_name (t) + "[" + ostr.str () + "]" + r; - } - else - r = emit_type_name (t) + "[]" + r; - - break; - } - case REFERENCE_TYPE: - { - tree t (TREE_TYPE (type)); - r = emit_type_name (t) + "&" + r; - break; - } - case POINTER_TYPE: - { - if (!TYPE_PTRMEM_P (type)) - { - tree t (TREE_TYPE (type)); - r = emit_type_name (t) + "*" + r; - } - else - r = "<pointer_to_member_type>"; - - break; - } - - // - // Fundamental types. - // - - case VOID_TYPE: - case REAL_TYPE: - case BOOLEAN_TYPE: - case INTEGER_TYPE: - { - type = TYPE_MAIN_VARIANT (type); - tree decl (TYPE_NAME (type)); - r = IDENTIFIER_POINTER (DECL_NAME (decl)) + r; - break; - } - default: - { - r = "<" + string (gcc_tree_code_name(tc)) + ">"; - break; - } - } - - return r; -} - -void parser::impl:: -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 that has been - // associated. - // - pragma_set prags; - - if (cur != begin) - { - decl_set::const_iterator i (cur); - 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 (decl, name, i->prag->pragma_name, i->prag->loc)) - prags.insert (*i->prag); - else - 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 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 (decl)); - - 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) - add_pragma (node, i->second); -} - -void parser::impl:: -process_named_pragmas (declaration const& decl, node& node) -{ - pragma_set prags; - - decl_pragmas::const_iterator i (decl_pragmas_.find (decl)); - - if (i != decl_pragmas_.end ()) - prags.insert (i->second.begin (), i->second.end ()); - - // Copy the resulting pragma set to context. - // - for (pragma_set::iterator i (prags.begin ()); i != prags.end (); ++i) - add_pragma (node, i->second); -} - -void parser::impl:: -add_pragma (node& n, pragma const& p) -{ - if (trace) - ts << "\t\t pragma " << p.pragma_name << endl; - - string const& k (p.context_name); - - if (p.add == 0) - { - n.set (k, p.value); - n.set (k + "-location", p.loc); - } - else - p.add (n, k, p.value, p.loc); -} - -void parser::impl:: -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 (p.loc) - << "db pragma '" << p.pragma_name << "' is not associated with a " - << "declaration" << endl; - error_++; - } - } -} - -string parser::impl:: -fq_scope (tree decl) -{ - string s, tmp; - - for (tree scope (CP_DECL_CONTEXT (decl)); - scope != global_namespace;) - { - tree prev (CP_DECL_CONTEXT (scope)); - - // If this is an inline namespace, pretend it doesn't exist. - // -#if BUILDING_GCC_MAJOR >= 8 - if (!is_nested_namespace (prev, scope, true)) -#else - if (!is_associated_namespace (prev, scope)) -#endif - { - tree n = DECL_NAME (scope); - - tmp = "::"; - tmp += (n != NULL_TREE ? IDENTIFIER_POINTER (n) : ""); - tmp += s; - s.swap (tmp); - } - - scope = prev; - } - - return s; -} - -// -// parser -// - -parser:: -~parser () -{ - // Needs parser::impl definition. -} - -parser:: -parser (options const& ops, - loc_pragmas& lp, - ns_loc_pragmas& nslp, - decl_pragmas& dp) - : impl_ (new impl (ops, lp, nslp, dp)) -{ -} - -unique_ptr<unit> parser:: -parse (tree global_scope, path const& main_file) -{ - return impl_->parse (global_scope, main_file); -} |