| /* Library interface to C++ front end. | |
| Copyright (C) 2014-2026 Free Software Foundation, Inc. | |
| This file is part of GCC. As it interacts with GDB through libcc1, | |
| they all become a single program as regards the GNU GPL's requirements. | |
| GCC is free software; you can redistribute it and/or modify it under | |
| the terms of the GNU General Public License as published by the Free | |
| Software Foundation; either version 3, or (at your option) any later | |
| version. | |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GCC; see the file COPYING3. If not see | |
| <http://www.gnu.org/licenses/>. */ | |
| #include <cc1plugin-config.h> | |
| #undef PACKAGE_NAME | |
| #undef PACKAGE_STRING | |
| #undef PACKAGE_TARNAME | |
| #undef PACKAGE_VERSION | |
| #include "../gcc/config.h" | |
| #undef PACKAGE_NAME | |
| #undef PACKAGE_STRING | |
| #undef PACKAGE_TARNAME | |
| #undef PACKAGE_VERSION | |
| #define INCLUDE_MEMORY | |
| #define INCLUDE_VECTOR | |
| #include "gcc-plugin.h" | |
| #include "system.h" | |
| #include "coretypes.h" | |
| #include "stringpool.h" | |
| #include "gcc-interface.h" | |
| #include "machmode.h" | |
| #include "vec.h" | |
| #include "double-int.h" | |
| #include "input.h" | |
| #include "alias.h" | |
| #include "symtab.h" | |
| #include "options.h" | |
| #include "wide-int.h" | |
| #include "inchash.h" | |
| #include "tree.h" | |
| #include "fold-const.h" | |
| #include "stor-layout.h" | |
| #include "cp-tree.h" | |
| #include "toplev.h" | |
| #include "timevar.h" | |
| #include "hash-table.h" | |
| #include "tm.h" | |
| #include "c-family/c-pragma.h" | |
| // #include "c-lang.h" | |
| #include "diagnostic.h" | |
| #include "langhooks.h" | |
| #include "langhooks-def.h" | |
| #include "decl.h" | |
| #include "function.h" | |
| #undef cfun // we want to assign to it, and function.h won't let us | |
| #include "callbacks.hh" | |
| #include "connection.hh" | |
| #include "marshall-cp.hh" | |
| #include "rpc.hh" | |
| #include "context.hh" | |
| using namespace cc1_plugin; | |
| static_assert (GCC_CP_SYMBOL_MASK >= GCC_CP_SYMBOL_END, | |
| "GCC_CP_SYMBOL_MASK >= GCC_CP_SYMBOL_END"); | |
| static void | |
| plugin_binding_oracle (enum cp_oracle_request kind, tree identifier) | |
| { | |
| enum gcc_cp_oracle_request request; | |
| gcc_assert (current_context != NULL); | |
| switch (kind) | |
| { | |
| case CP_ORACLE_IDENTIFIER: | |
| request = GCC_CP_ORACLE_IDENTIFIER; | |
| break; | |
| default: | |
| abort (); | |
| } | |
| int ignore; | |
| cc1_plugin::call (current_context, "binding_oracle", &ignore, | |
| request, IDENTIFIER_POINTER (identifier)); | |
| } | |
| static int push_count; | |
| /* at_function_scope_p () tests cfun, indicating we're actually | |
| compiling the function, but we don't even set it when pretending to | |
| enter a function scope. We use this distinction to tell these two | |
| cases apart: we don't want to define e.g. class names in the user | |
| expression function's scope, when they're local to the original | |
| function, because they'd get the wrong linkage name. */ | |
| static bool | |
| at_fake_function_scope_p () | |
| { | |
| return (!cfun || cfun->decl != current_function_decl) | |
| && current_scope () == current_function_decl; | |
| } | |
| static void | |
| push_fake_function (tree fndecl, scope_kind kind = sk_function_parms) | |
| { | |
| current_function_decl = fndecl; | |
| begin_scope (kind, fndecl); | |
| ++function_depth; | |
| begin_scope (sk_block, NULL); | |
| } | |
| static void | |
| pop_scope () | |
| { | |
| if (toplevel_bindings_p () && current_namespace == global_namespace) | |
| pop_from_top_level (); | |
| else if (at_namespace_scope_p ()) | |
| pop_namespace (); | |
| else if (at_class_scope_p ()) | |
| popclass (); | |
| else | |
| { | |
| gcc_assert (at_fake_function_scope_p ()); | |
| gcc_assert (!at_function_scope_p ()); | |
| gcc_assert (current_binding_level->kind == sk_block | |
| && current_binding_level->this_entity == NULL); | |
| leave_scope (); | |
| --function_depth; | |
| gcc_assert (current_binding_level->this_entity | |
| == current_function_decl); | |
| leave_scope (); | |
| current_function_decl = NULL; | |
| for (cp_binding_level *scope = current_binding_level; | |
| scope; scope = scope->level_chain) | |
| if (scope->kind == sk_function_parms) | |
| { | |
| current_function_decl = scope->this_entity; | |
| break; | |
| } | |
| } | |
| } | |
| static void | |
| supplement_binding (cxx_binding *binding, tree decl) | |
| { | |
| /* FIXME: this is pretty much a copy of supplement_binding_1 in | |
| ../gcc/cp/name-lookup.c; the few replaced/removed bits are marked | |
| with "// _1:". */ | |
| tree bval = binding->value; | |
| bool ok = true; | |
| tree target_bval = strip_using_decl (bval); | |
| tree target_decl = strip_using_decl (decl); | |
| if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl) | |
| && target_decl != target_bval | |
| && (TREE_CODE (target_bval) != TYPE_DECL | |
| /* We allow pushing an enum multiple times in a class | |
| template in order to handle late matching of underlying | |
| type on an opaque-enum-declaration followed by an | |
| enum-specifier. */ | |
| || (processing_template_decl | |
| && TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE | |
| && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE | |
| && (dependent_type_p (ENUM_UNDERLYING_TYPE | |
| (TREE_TYPE (target_decl))) | |
| || dependent_type_p (ENUM_UNDERLYING_TYPE | |
| (TREE_TYPE (target_bval))))))) | |
| /* The new name is the type name. */ | |
| binding->type = decl; | |
| else if (/* TARGET_BVAL is null when push_class_level_binding moves | |
| an inherited type-binding out of the way to make room | |
| for a new value binding. */ | |
| !target_bval | |
| /* TARGET_BVAL is error_mark_node when TARGET_DECL's name | |
| has been used in a non-class scope prior declaration. | |
| In that case, we should have already issued a | |
| diagnostic; for graceful error recovery purpose, pretend | |
| this was the intended declaration for that name. */ | |
| || target_bval == error_mark_node | |
| /* If TARGET_BVAL is anticipated but has not yet been | |
| declared, pretend it is not there at all. */ | |
| || (TREE_CODE (target_bval) == FUNCTION_DECL | |
| && DECL_IS_UNDECLARED_BUILTIN (target_bval))) | |
| binding->value = decl; | |
| else if (TREE_CODE (target_bval) == TYPE_DECL | |
| && DECL_ARTIFICIAL (target_bval) | |
| && target_decl != target_bval | |
| && (TREE_CODE (target_decl) != TYPE_DECL | |
| || same_type_p (TREE_TYPE (target_decl), | |
| TREE_TYPE (target_bval)))) | |
| { | |
| /* The old binding was a type name. It was placed in | |
| VALUE field because it was thought, at the point it was | |
| declared, to be the only entity with such a name. Move the | |
| type name into the type slot; it is now hidden by the new | |
| binding. */ | |
| binding->type = bval; | |
| binding->value = decl; | |
| binding->value_is_inherited = false; | |
| } | |
| else if (TREE_CODE (target_bval) == TYPE_DECL | |
| && TREE_CODE (target_decl) == TYPE_DECL | |
| && DECL_NAME (target_decl) == DECL_NAME (target_bval) | |
| && binding->scope->kind != sk_class | |
| && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval)) | |
| /* If either type involves template parameters, we must | |
| wait until instantiation. */ | |
| || uses_template_parms (TREE_TYPE (target_decl)) | |
| || uses_template_parms (TREE_TYPE (target_bval)))) | |
| /* We have two typedef-names, both naming the same type to have | |
| the same name. In general, this is OK because of: | |
| [dcl.typedef] | |
| In a given scope, a typedef specifier can be used to redefine | |
| the name of any type declared in that scope to refer to the | |
| type to which it already refers. | |
| However, in class scopes, this rule does not apply due to the | |
| stricter language in [class.mem] prohibiting redeclarations of | |
| members. */ | |
| ok = false; | |
| /* There can be two block-scope declarations of the same variable, | |
| so long as they are `extern' declarations. However, there cannot | |
| be two declarations of the same static data member: | |
| [class.mem] | |
| A member shall not be declared twice in the | |
| member-specification. */ | |
| else if (VAR_P (target_decl) | |
| && VAR_P (target_bval) | |
| && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval) | |
| && !DECL_CLASS_SCOPE_P (target_decl)) | |
| { | |
| duplicate_decls (decl, binding->value); | |
| ok = false; | |
| } | |
| else if (TREE_CODE (decl) == NAMESPACE_DECL | |
| && TREE_CODE (bval) == NAMESPACE_DECL | |
| && DECL_NAMESPACE_ALIAS (decl) | |
| && DECL_NAMESPACE_ALIAS (bval) | |
| && ORIGINAL_NAMESPACE (bval) == ORIGINAL_NAMESPACE (decl)) | |
| /* [namespace.alias] | |
| In a declarative region, a namespace-alias-definition can be | |
| used to redefine a namespace-alias declared in that declarative | |
| region to refer only to the namespace to which it already | |
| refers. */ | |
| ok = false; | |
| else | |
| { | |
| // _1: diagnose_name_conflict (decl, bval); | |
| ok = false; | |
| } | |
| gcc_assert (ok); // _1: return ok; | |
| } | |
| static void | |
| reactivate_decl (tree decl, cp_binding_level *b) | |
| { | |
| bool in_function_p = TREE_CODE (b->this_entity) == FUNCTION_DECL; | |
| gcc_assert (in_function_p | |
| || (b == current_binding_level | |
| && !at_class_scope_p ())); | |
| tree id = DECL_NAME (decl); | |
| tree type = NULL_TREE; | |
| if (TREE_CODE (decl) == TYPE_DECL) | |
| type = TREE_TYPE (decl); | |
| if (type && TYPE_NAME (type) == decl | |
| && (RECORD_OR_UNION_CODE_P (TREE_CODE (type)) | |
| || TREE_CODE (type) == ENUMERAL_TYPE)) | |
| { | |
| gcc_assert (in_function_p && DECL_CONTEXT (decl) == b->this_entity); | |
| type = TREE_TYPE (decl); | |
| } | |
| else | |
| { | |
| gcc_assert (DECL_CONTEXT (decl) == b->this_entity | |
| || DECL_CONTEXT (decl) == global_namespace | |
| || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL); | |
| type = NULL_TREE; | |
| } | |
| /* Adjust IDENTIFIER_BINDING to what it would have been if we were | |
| at binding level B. Save the binding chain up to that point in | |
| [binding, *chainp), and take note of the outermost bindings found | |
| before B. */ | |
| cxx_binding *binding = IDENTIFIER_BINDING (id), **chainp = NULL; | |
| tree *shadowing_type_p = NULL; | |
| if (binding) | |
| { | |
| cp_binding_level *bc = current_binding_level; | |
| for (cxx_binding *prev_binding = binding; | |
| prev_binding; prev_binding = prev_binding->previous) | |
| { | |
| while (bc != b && bc != prev_binding->scope) | |
| bc = bc->level_chain; | |
| if (bc == b) | |
| { | |
| if (!chainp) | |
| binding = NULL; | |
| break; | |
| } | |
| chainp = &prev_binding->previous; | |
| if (type) | |
| for (tree tshadow = prev_binding->scope->type_shadowed; | |
| tshadow; tshadow = TREE_CHAIN (tshadow)) | |
| if (TREE_PURPOSE (tshadow) == id) | |
| { | |
| shadowing_type_p = &TREE_VALUE (tshadow); | |
| break; | |
| } | |
| } | |
| } | |
| if (chainp) | |
| { | |
| IDENTIFIER_BINDING (id) = *chainp; | |
| *chainp = NULL; | |
| } | |
| /* Like push_local_binding, supplement or add a binding to the | |
| desired level. */ | |
| if (IDENTIFIER_BINDING (id) && IDENTIFIER_BINDING (id)->scope == b) | |
| supplement_binding (IDENTIFIER_BINDING (id), decl); | |
| else | |
| push_binding (id, decl, b); | |
| /* Now restore the binding chain we'd temporarily removed. */ | |
| if (chainp) | |
| { | |
| *chainp = IDENTIFIER_BINDING (id); | |
| IDENTIFIER_BINDING (id) = binding; | |
| if (type) | |
| { | |
| /* Insert the new type binding in the shadowing_type_p | |
| TREE_VALUE chain. */ | |
| tree shadowed_type = NULL_TREE; | |
| if (shadowing_type_p) | |
| { | |
| shadowed_type = *shadowing_type_p; | |
| *shadowing_type_p = type; | |
| } | |
| b->type_shadowed = tree_cons (id, shadowed_type, b->type_shadowed); | |
| TREE_TYPE (b->type_shadowed) = type; | |
| } | |
| } | |
| else if (type) | |
| { | |
| /* Our new binding is the active one, so shadow the earlier | |
| binding. */ | |
| b->type_shadowed = tree_cons (id, REAL_IDENTIFIER_TYPE_VALUE (id), | |
| b->type_shadowed); | |
| TREE_TYPE (b->type_shadowed) = type; | |
| SET_IDENTIFIER_TYPE_VALUE (id, type); | |
| } | |
| /* Record that we have a binding for ID, like add_decl_to_level. */ | |
| tree node = build_tree_list (NULL_TREE, decl); | |
| TREE_CHAIN (node) = b->names; | |
| b->names = node; | |
| } | |
| static void | |
| plugin_pragma_push_user_expression (cpp_reader *) | |
| { | |
| if (push_count++) | |
| return; | |
| gcc_assert (!current_class_ptr); | |
| gcc_assert (!current_class_ref); | |
| gcc_assert (!cp_binding_oracle); | |
| cp_binding_oracle = plugin_binding_oracle; | |
| /* Make the function containing the user expression a global | |
| friend, so as to bypass access controls in it. */ | |
| if (at_function_scope_p ()) | |
| set_global_friend (current_function_decl); | |
| gcc_assert (at_function_scope_p ()); | |
| function *save_cfun = cfun; | |
| cp_binding_level *orig_binding_level = current_binding_level; | |
| { | |
| int success; | |
| cc1_plugin::call (current_context, "enter_scope", &success); | |
| } | |
| gcc_assert (at_fake_function_scope_p () || at_function_scope_p ()); | |
| function *unchanged_cfun = cfun; | |
| tree changed_func_decl = current_function_decl; | |
| gcc_assert (current_class_type == DECL_CONTEXT (current_function_decl) | |
| || !(RECORD_OR_UNION_CODE_P | |
| (TREE_CODE (DECL_CONTEXT (current_function_decl))))); | |
| push_fake_function (save_cfun->decl, sk_block); | |
| current_class_type = NULL_TREE; | |
| if (unchanged_cfun) | |
| { | |
| /* If we get here, GDB did NOT change the context. */ | |
| gcc_assert (cfun == save_cfun); | |
| gcc_assert (at_function_scope_p ()); | |
| gcc_assert (orig_binding_level | |
| == current_binding_level->level_chain->level_chain); | |
| } | |
| else | |
| { | |
| cfun = save_cfun; | |
| gcc_assert (at_function_scope_p ()); | |
| cp_binding_level *b = current_binding_level->level_chain; | |
| gcc_assert (b->this_entity == cfun->decl); | |
| /* Reactivate local names from the previous context. Use | |
| IDENTIFIER_MARKED to avoid reactivating shadowed names. */ | |
| for (cp_binding_level *level = orig_binding_level;;) | |
| { | |
| for (tree name = level->names; | |
| name; name = TREE_CHAIN (name)) | |
| { | |
| tree decl = name; | |
| if (TREE_CODE (decl) == TREE_LIST) | |
| decl = TREE_VALUE (decl); | |
| if (IDENTIFIER_MARKED (DECL_NAME (decl))) | |
| continue; | |
| IDENTIFIER_MARKED (DECL_NAME (decl)) = 1; | |
| reactivate_decl (decl, b); | |
| } | |
| if (level->kind == sk_function_parms | |
| && level->this_entity == cfun->decl) | |
| break; | |
| gcc_assert (!level->this_entity); | |
| level = level->level_chain; | |
| } | |
| /* Now, clear the markers. */ | |
| for (tree name = b->names; name; name = TREE_CHAIN (name)) | |
| { | |
| tree decl = name; | |
| if (TREE_CODE (decl) == TREE_LIST) | |
| decl = TREE_VALUE (decl); | |
| gcc_assert (IDENTIFIER_MARKED (DECL_NAME (decl))); | |
| IDENTIFIER_MARKED (DECL_NAME (decl)) = 0; | |
| } | |
| } | |
| if (unchanged_cfun || DECL_OBJECT_MEMBER_FUNCTION_P (changed_func_decl)) | |
| { | |
| /* Check whether the oracle supplies us with a "this", and if | |
| so, arrange for data members and this itself to be | |
| usable. */ | |
| tree this_val = lookup_name (get_identifier ("this")); | |
| current_class_ref = !this_val ? NULL_TREE | |
| : cp_build_indirect_ref (input_location, this_val, RO_NULL, | |
| tf_warning_or_error); | |
| current_class_ptr = this_val; | |
| } | |
| } | |
| static void | |
| plugin_pragma_pop_user_expression (cpp_reader *) | |
| { | |
| if (--push_count) | |
| return; | |
| gcc_assert (cp_binding_oracle); | |
| gcc_assert (at_function_scope_p ()); | |
| function *save_cfun = cfun; | |
| current_class_ptr = NULL_TREE; | |
| current_class_ref = NULL_TREE; | |
| cfun = NULL; | |
| pop_scope (); | |
| if (RECORD_OR_UNION_CODE_P (TREE_CODE (DECL_CONTEXT (current_function_decl)))) | |
| current_class_type = DECL_CONTEXT (current_function_decl); | |
| { | |
| int success; | |
| cc1_plugin::call (current_context, "leave_scope", &success); | |
| } | |
| if (!cfun) | |
| cfun = save_cfun; | |
| else | |
| gcc_assert (cfun == save_cfun); | |
| cp_binding_oracle = NULL; | |
| gcc_assert (at_function_scope_p ()); | |
| } | |
| static void | |
| plugin_init_extra_pragmas (void *, void *) | |
| { | |
| c_register_pragma ("GCC", "push_user_expression", plugin_pragma_push_user_expression); | |
| c_register_pragma ("GCC", "pop_user_expression", plugin_pragma_pop_user_expression); | |
| /* FIXME: this one should go once we get GDB to use push and pop. */ | |
| c_register_pragma ("GCC", "user_expression", plugin_pragma_push_user_expression); | |
| } | |
| static decl_addr_value | |
| build_decl_addr_value (tree decl, gcc_address address) | |
| { | |
| decl_addr_value value = { | |
| decl, | |
| build_int_cst_type (ptr_type_node, address) | |
| }; | |
| return value; | |
| } | |
| static decl_addr_value * | |
| record_decl_address (plugin_context *ctx, decl_addr_value value) | |
| { | |
| decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT); | |
| gcc_assert (*slot == NULL); | |
| *slot | |
| = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value))); | |
| **slot = value; | |
| /* We don't want GCC to warn about e.g. static functions | |
| without a code definition. */ | |
| suppress_warning (value.decl); | |
| return *slot; | |
| } | |
| // Maybe rewrite a decl to its address. | |
| static tree | |
| address_rewriter (tree *in, int *walk_subtrees, void *arg) | |
| { | |
| plugin_context *ctx = (plugin_context *) arg; | |
| if (!DECL_P (*in) | |
| || TREE_CODE (*in) == NAMESPACE_DECL | |
| || DECL_NAME (*in) == NULL_TREE) | |
| return NULL_TREE; | |
| decl_addr_value value; | |
| value.decl = *in; | |
| decl_addr_value *found_value = ctx->address_map.find (&value); | |
| if (found_value != NULL) | |
| ; | |
| else if (HAS_DECL_ASSEMBLER_NAME_P (*in)) | |
| { | |
| gcc_address address; | |
| if (!cc1_plugin::call (ctx, "address_oracle", &address, | |
| IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (*in)))) | |
| return NULL_TREE; | |
| if (address == 0) | |
| return NULL_TREE; | |
| // Insert the decl into the address map in case it is referenced | |
| // again. | |
| value = build_decl_addr_value (value.decl, address); | |
| found_value = record_decl_address (ctx, value); | |
| } | |
| else | |
| return NULL_TREE; | |
| if (found_value->address != error_mark_node) | |
| { | |
| // We have an address for the decl, so rewrite the tree. | |
| tree ptr_type = build_pointer_type (TREE_TYPE (*in)); | |
| *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in), | |
| fold_build1 (CONVERT_EXPR, ptr_type, | |
| found_value->address)); | |
| } | |
| *walk_subtrees = 0; | |
| return NULL_TREE; | |
| } | |
| // When generating code for gdb, we want to be able to use absolute | |
| // addresses to refer to otherwise external objects that gdb knows | |
| // about. gdb passes in these addresses when building decls, and then | |
| // before gimplification we go through the trees, rewriting uses to | |
| // the equivalent of "*(TYPE *) ADDR". | |
| static void | |
| rewrite_decls_to_addresses (void *function_in, void *) | |
| { | |
| tree function = (tree) function_in; | |
| // Do nothing if we're not in gdb. | |
| if (current_context == NULL) | |
| return; | |
| walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context, | |
| NULL); | |
| } | |
| static inline tree | |
| safe_push_template_decl (tree decl) | |
| { | |
| void (*save_oracle) (enum cp_oracle_request, tree identifier); | |
| save_oracle = cp_binding_oracle; | |
| cp_binding_oracle = NULL; | |
| tree ret = push_template_decl (decl); | |
| cp_binding_oracle = save_oracle; | |
| return ret; | |
| } | |
| static inline tree | |
| safe_pushtag (tree name, tree type) | |
| { | |
| void (*save_oracle) (enum cp_oracle_request, tree identifier); | |
| save_oracle = cp_binding_oracle; | |
| cp_binding_oracle = NULL; | |
| tree ret = pushtag (name, type); | |
| cp_binding_oracle = save_oracle; | |
| return ret; | |
| } | |
| static inline tree | |
| safe_pushdecl (tree decl) | |
| { | |
| void (*save_oracle) (enum cp_oracle_request, tree identifier); | |
| save_oracle = cp_binding_oracle; | |
| cp_binding_oracle = NULL; | |
| tree ret = pushdecl (decl); | |
| cp_binding_oracle = save_oracle; | |
| return ret; | |
| } | |
| int | |
| plugin_push_namespace (cc1_plugin::connection *, | |
| const char *name) | |
| { | |
| if (name && !*name) | |
| push_to_top_level (); | |
| else | |
| push_namespace (name ? get_identifier (name) : NULL); | |
| return 1; | |
| } | |
| int | |
| plugin_push_class (cc1_plugin::connection *, | |
| gcc_type type_in) | |
| { | |
| tree type = convert_in (type_in); | |
| gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (type))); | |
| gcc_assert (TYPE_CONTEXT (type) == FROB_CONTEXT (current_scope ())); | |
| pushclass (type); | |
| return 1; | |
| } | |
| int | |
| plugin_push_function (cc1_plugin::connection *, | |
| gcc_decl function_decl_in) | |
| { | |
| tree fndecl = convert_in (function_decl_in); | |
| gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL); | |
| gcc_assert (DECL_CONTEXT (fndecl) == FROB_CONTEXT (current_scope ())); | |
| push_fake_function (fndecl); | |
| return 1; | |
| } | |
| int | |
| plugin_pop_binding_level (cc1_plugin::connection *) | |
| { | |
| pop_scope (); | |
| return 1; | |
| } | |
| int | |
| plugin_reactivate_decl (cc1_plugin::connection *, | |
| gcc_decl decl_in, | |
| gcc_decl scope_in) | |
| { | |
| tree decl = convert_in (decl_in); | |
| tree scope = convert_in (scope_in); | |
| gcc_assert (VAR_P (decl) | |
| || TREE_CODE (decl) == FUNCTION_DECL | |
| || TREE_CODE (decl) == TYPE_DECL); | |
| cp_binding_level *b; | |
| if (scope) | |
| { | |
| gcc_assert (TREE_CODE (scope) == FUNCTION_DECL); | |
| for (b = current_binding_level; | |
| b->this_entity != scope; | |
| b = b->level_chain) | |
| gcc_assert (b->this_entity != global_namespace); | |
| } | |
| else | |
| { | |
| gcc_assert (!at_class_scope_p ()); | |
| b = current_binding_level; | |
| } | |
| reactivate_decl (decl, b); | |
| return 1; | |
| } | |
| static tree | |
| get_current_scope () | |
| { | |
| tree decl; | |
| if (at_namespace_scope_p ()) | |
| decl = current_namespace; | |
| else if (at_class_scope_p ()) | |
| decl = TYPE_NAME (current_class_type); | |
| else if (at_fake_function_scope_p () || at_function_scope_p ()) | |
| decl = current_function_decl; | |
| else | |
| gcc_unreachable (); | |
| return decl; | |
| } | |
| gcc_decl | |
| plugin_get_current_binding_level_decl (cc1_plugin::connection *) | |
| { | |
| tree decl = get_current_scope (); | |
| return convert_out (decl); | |
| } | |
| int | |
| plugin_make_namespace_inline (cc1_plugin::connection *) | |
| { | |
| tree inline_ns = current_namespace; | |
| gcc_assert (toplevel_bindings_p ()); | |
| gcc_assert (inline_ns != global_namespace); | |
| tree parent_ns = CP_DECL_CONTEXT (inline_ns); | |
| if (DECL_NAMESPACE_INLINE_P (inline_ns)) | |
| return 0; | |
| DECL_NAMESPACE_INLINE_P (inline_ns) = true; | |
| vec_safe_push (DECL_NAMESPACE_INLINEES (parent_ns), inline_ns); | |
| return 1; | |
| } | |
| int | |
| plugin_add_using_namespace (cc1_plugin::connection *, | |
| gcc_decl used_ns_in) | |
| { | |
| tree used_ns = convert_in (used_ns_in); | |
| gcc_assert (TREE_CODE (used_ns) == NAMESPACE_DECL); | |
| finish_using_directive (used_ns, NULL_TREE); | |
| return 1; | |
| } | |
| int | |
| plugin_add_namespace_alias (cc1_plugin::connection *, | |
| const char *id, | |
| gcc_decl target_in) | |
| { | |
| tree name = get_identifier (id); | |
| tree target = convert_in (target_in); | |
| do_namespace_alias (input_location, name, target); | |
| return 1; | |
| } | |
| static inline void | |
| set_access_flags (tree decl, enum gcc_cp_symbol_kind flags) | |
| { | |
| gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !DECL_CLASS_SCOPE_P (decl)); | |
| switch (flags & GCC_CP_ACCESS_MASK) | |
| { | |
| case GCC_CP_ACCESS_PRIVATE: | |
| TREE_PRIVATE (decl) = true; | |
| current_access_specifier = access_private_node; | |
| break; | |
| case GCC_CP_ACCESS_PROTECTED: | |
| TREE_PROTECTED (decl) = true; | |
| current_access_specifier = access_protected_node; | |
| break; | |
| case GCC_CP_ACCESS_PUBLIC: | |
| current_access_specifier = access_public_node; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| int | |
| plugin_add_using_decl (cc1_plugin::connection *, | |
| enum gcc_cp_symbol_kind flags, | |
| gcc_decl target_in) | |
| { | |
| tree target = convert_in (target_in); | |
| gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_USING); | |
| gcc_assert (!(flags & GCC_CP_FLAG_MASK)); | |
| enum gcc_cp_symbol_kind acc_flags; | |
| acc_flags = (enum gcc_cp_symbol_kind) (flags & GCC_CP_ACCESS_MASK); | |
| gcc_assert (!template_parm_scope_p ()); | |
| bool class_member_p = at_class_scope_p (); | |
| gcc_assert (!(acc_flags & GCC_CP_ACCESS_MASK) == !class_member_p); | |
| tree identifier = DECL_NAME (target); | |
| tree tcontext = DECL_CONTEXT (target); | |
| if (UNSCOPED_ENUM_P (tcontext)) | |
| tcontext = CP_TYPE_CONTEXT (tcontext); | |
| if (class_member_p) | |
| { | |
| tree decl = do_class_using_decl (tcontext, identifier); | |
| set_access_flags (decl, flags); | |
| finish_member_declaration (decl); | |
| } | |
| else | |
| { | |
| /* We can't be at local scope. */ | |
| gcc_assert (at_namespace_scope_p ()); | |
| finish_nonmember_using_decl (tcontext, identifier); | |
| } | |
| return 1; | |
| } | |
| static tree | |
| build_named_class_type (enum tree_code code, | |
| tree id, | |
| location_t loc) | |
| { | |
| /* See at_fake_function_scope_p. */ | |
| gcc_assert (!at_function_scope_p ()); | |
| tree type = make_class_type (code); | |
| tree type_decl = build_decl (loc, TYPE_DECL, id, type); | |
| TYPE_NAME (type) = type_decl; | |
| TYPE_STUB_DECL (type) = type_decl; | |
| DECL_CONTEXT (type_decl) = TYPE_CONTEXT (type); | |
| return type_decl; | |
| } | |
| /* Abuse an unused field of the dummy template parms entry to hold the | |
| parm list. */ | |
| #define TP_PARM_LIST TREE_TYPE (current_template_parms) | |
| gcc_decl | |
| plugin_build_decl (cc1_plugin::connection *self, | |
| const char *name, | |
| enum gcc_cp_symbol_kind sym_kind, | |
| gcc_type sym_type_in, | |
| const char *substitution_name, | |
| gcc_address address, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| gcc_assert (!name || !strchr (name, ':')); // FIXME: this can go eventually. | |
| enum tree_code code; | |
| tree decl; | |
| tree sym_type = convert_in (sym_type_in); | |
| enum gcc_cp_symbol_kind sym_flags; | |
| sym_flags = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_FLAG_MASK); | |
| enum gcc_cp_symbol_kind acc_flags; | |
| acc_flags = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_ACCESS_MASK); | |
| sym_kind = (enum gcc_cp_symbol_kind) (sym_kind & GCC_CP_SYMBOL_MASK); | |
| switch (sym_kind) | |
| { | |
| case GCC_CP_SYMBOL_FUNCTION: | |
| code = FUNCTION_DECL; | |
| gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_FUNCTION)); | |
| break; | |
| case GCC_CP_SYMBOL_VARIABLE: | |
| code = VAR_DECL; | |
| gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_VARIABLE)); | |
| break; | |
| case GCC_CP_SYMBOL_TYPEDEF: | |
| code = TYPE_DECL; | |
| gcc_assert (!sym_flags); | |
| break; | |
| case GCC_CP_SYMBOL_CLASS: | |
| code = RECORD_TYPE; | |
| gcc_assert (!(sym_flags & ~GCC_CP_FLAG_MASK_CLASS)); | |
| gcc_assert (!sym_type); | |
| break; | |
| case GCC_CP_SYMBOL_UNION: | |
| code = UNION_TYPE; | |
| gcc_assert (!sym_flags); | |
| gcc_assert (!sym_type); | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| bool template_decl_p = template_parm_scope_p (); | |
| if (template_decl_p) | |
| { | |
| gcc_assert (code == FUNCTION_DECL || code == RECORD_TYPE | |
| || code == TYPE_DECL); | |
| /* Finish the template parm list that started this template parm. */ | |
| end_template_parm_list (TP_PARM_LIST); | |
| gcc_assert (!address); | |
| gcc_assert (!substitution_name); | |
| } | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| bool class_member_p = at_class_scope_p (); | |
| bool ctor = false, dtor = false, assop = false; | |
| tree_code opcode = ERROR_MARK; | |
| gcc_assert (!(acc_flags & GCC_CP_ACCESS_MASK) == !class_member_p); | |
| tree identifier; | |
| if (code != FUNCTION_DECL | |
| || !(sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION)) | |
| { | |
| if (name) | |
| identifier = get_identifier (name); | |
| else | |
| { | |
| gcc_assert (RECORD_OR_UNION_CODE_P (code)); | |
| identifier = make_anon_name (); | |
| } | |
| } | |
| if (code == FUNCTION_DECL) | |
| { | |
| if (sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION) | |
| { | |
| #define CHARS2(f,s) (((unsigned char)f << CHAR_BIT) | (unsigned char)s) | |
| switch (CHARS2 (name[0], name[1])) | |
| { | |
| case CHARS2 ('C', 0x0): // ctor base declaration | |
| case CHARS2 ('C', ' '): | |
| case CHARS2 ('C', '1'): | |
| case CHARS2 ('C', '2'): | |
| case CHARS2 ('C', '4'): | |
| ctor = true; | |
| cdtor: | |
| gcc_assert (!address); | |
| gcc_assert (!substitution_name); | |
| identifier = DECL_NAME (TYPE_NAME (current_class_type)); | |
| break; | |
| case CHARS2 ('D', 0x0): // dtor base declaration | |
| case CHARS2 ('D', ' '): | |
| case CHARS2 ('D', '0'): | |
| case CHARS2 ('D', '1'): | |
| case CHARS2 ('D', '2'): | |
| case CHARS2 ('D', '4'): | |
| gcc_assert (!template_decl_p); | |
| dtor = true; | |
| goto cdtor; | |
| case CHARS2 ('n', 'w'): // operator new | |
| opcode = NEW_EXPR; | |
| break; | |
| case CHARS2 ('n', 'a'): // operator new[] | |
| opcode = VEC_NEW_EXPR; | |
| break; | |
| case CHARS2 ('d', 'l'): // operator delete | |
| opcode = DELETE_EXPR; | |
| break; | |
| case CHARS2 ('d', 'a'): // operator delete[] | |
| opcode = VEC_DELETE_EXPR; | |
| break; | |
| case CHARS2 ('p', 's'): // operator + (unary) | |
| opcode = PLUS_EXPR; | |
| break; | |
| case CHARS2 ('n', 'g'): // operator - (unary) | |
| opcode = MINUS_EXPR; | |
| break; | |
| case CHARS2 ('a', 'd'): // operator & (unary) | |
| opcode = BIT_AND_EXPR; | |
| break; | |
| case CHARS2 ('d', 'e'): // operator * (unary) | |
| opcode = MULT_EXPR; | |
| break; | |
| case CHARS2 ('c', 'o'): // operator ~ | |
| opcode = BIT_NOT_EXPR; | |
| break; | |
| case CHARS2 ('p', 'l'): // operator + | |
| opcode = PLUS_EXPR; | |
| break; | |
| case CHARS2 ('m', 'i'): // operator - | |
| opcode = MINUS_EXPR; | |
| break; | |
| case CHARS2 ('m', 'l'): // operator * | |
| opcode = MULT_EXPR; | |
| break; | |
| case CHARS2 ('d', 'v'): // operator / | |
| opcode = TRUNC_DIV_EXPR; | |
| break; | |
| case CHARS2 ('r', 'm'): // operator % | |
| opcode = TRUNC_MOD_EXPR; | |
| break; | |
| case CHARS2 ('a', 'n'): // operator & | |
| opcode = BIT_AND_EXPR; | |
| break; | |
| case CHARS2 ('o', 'r'): // operator | | |
| opcode = BIT_IOR_EXPR; | |
| break; | |
| case CHARS2 ('e', 'o'): // operator ^ | |
| opcode = BIT_XOR_EXPR; | |
| break; | |
| case CHARS2 ('a', 'S'): // operator = | |
| opcode = NOP_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('p', 'L'): // operator += | |
| opcode = PLUS_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('m', 'I'): // operator -= | |
| opcode = MINUS_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('m', 'L'): // operator *= | |
| opcode = MULT_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('d', 'V'): // operator /= | |
| opcode = TRUNC_DIV_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('r', 'M'): // operator %= | |
| opcode = TRUNC_MOD_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('a', 'N'): // operator &= | |
| opcode = BIT_AND_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('o', 'R'): // operator |= | |
| opcode = BIT_IOR_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('e', 'O'): // operator ^= | |
| opcode = BIT_XOR_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('l', 's'): // operator << | |
| opcode = LSHIFT_EXPR; | |
| break; | |
| case CHARS2 ('r', 's'): // operator >> | |
| opcode = RSHIFT_EXPR; | |
| break; | |
| case CHARS2 ('l', 'S'): // operator <<= | |
| opcode = LSHIFT_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('r', 'S'): // operator >>= | |
| opcode = RSHIFT_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('e', 'q'): // operator == | |
| opcode = EQ_EXPR; | |
| break; | |
| case CHARS2 ('n', 'e'): // operator != | |
| opcode = NE_EXPR; | |
| break; | |
| case CHARS2 ('l', 't'): // operator < | |
| opcode = LT_EXPR; | |
| break; | |
| case CHARS2 ('g', 't'): // operator > | |
| opcode = GT_EXPR; | |
| break; | |
| case CHARS2 ('l', 'e'): // operator <= | |
| opcode = LE_EXPR; | |
| break; | |
| case CHARS2 ('g', 'e'): // operator >= | |
| opcode = GE_EXPR; | |
| break; | |
| case CHARS2 ('n', 't'): // operator ! | |
| opcode = TRUTH_NOT_EXPR; | |
| break; | |
| case CHARS2 ('a', 'a'): // operator && | |
| opcode = TRUTH_ANDIF_EXPR; | |
| break; | |
| case CHARS2 ('o', 'o'): // operator || | |
| opcode = TRUTH_ORIF_EXPR; | |
| break; | |
| case CHARS2 ('p', 'p'): // operator ++ | |
| opcode = POSTINCREMENT_EXPR; | |
| break; | |
| case CHARS2 ('m', 'm'): // operator -- | |
| /* This stands for either one as an operator name, and | |
| "pp" and "mm" stand for POST??CREMENT, but for some | |
| reason the parser uses this opcode name for | |
| operator--; let's follow their practice. */ | |
| opcode = PREDECREMENT_EXPR; | |
| break; | |
| case CHARS2 ('c', 'm'): // operator , | |
| opcode = COMPOUND_EXPR; | |
| break; | |
| case CHARS2 ('p', 'm'): // operator ->* | |
| opcode = MEMBER_REF; | |
| break; | |
| case CHARS2 ('p', 't'): // operator -> | |
| opcode = COMPONENT_REF; | |
| break; | |
| case CHARS2 ('c', 'l'): // operator () | |
| opcode = CALL_EXPR; | |
| break; | |
| case CHARS2 ('i', 'x'): // operator [] | |
| opcode = ARRAY_REF; | |
| break; | |
| case CHARS2 ('c', 'v'): // operator <T> (conversion operator) | |
| identifier = make_conv_op_name (TREE_TYPE (sym_type)); | |
| break; | |
| // C++11-only: | |
| case CHARS2 ('l', 'i'): // operator "" <id> | |
| { | |
| char *id = (char *)name + 2; | |
| bool freeid = false; | |
| if (*id >= '0' && *id <= '9') | |
| { | |
| unsigned len = 0; | |
| do | |
| { | |
| len *= 10; | |
| len += id[0] - '0'; | |
| id++; | |
| } | |
| while (*id && *id >= '0' && *id <= '9'); | |
| id = xstrndup (id, len); | |
| freeid = true; | |
| } | |
| identifier = cp_literal_operator_id (id); | |
| if (freeid) | |
| free (id); | |
| } | |
| break; | |
| case CHARS2 ('q', 'u'): // ternary operator, not overloadable. | |
| default: | |
| gcc_unreachable (); | |
| } | |
| if (opcode != ERROR_MARK) | |
| identifier = ovl_op_identifier (assop, opcode); | |
| } | |
| decl = build_lang_decl_loc (loc, code, identifier, sym_type); | |
| /* FIXME: current_lang_name is lang_name_c while compiling an | |
| extern "C" function, and we haven't switched to a global | |
| context at this point, and this breaks function | |
| overloading. */ | |
| SET_DECL_LANGUAGE (decl, lang_cplusplus); | |
| if (TREE_CODE (sym_type) == METHOD_TYPE) | |
| DECL_ARGUMENTS (decl) = build_this_parm (decl, current_class_type, | |
| cp_type_quals (sym_type)); | |
| for (tree arg = TREE_CODE (sym_type) == METHOD_TYPE | |
| ? TREE_CHAIN (TYPE_ARG_TYPES (sym_type)) | |
| : TYPE_ARG_TYPES (sym_type); | |
| arg && arg != void_list_node; | |
| arg = TREE_CHAIN (arg)) | |
| { | |
| tree parm = cp_build_parm_decl (decl, NULL_TREE, TREE_VALUE (arg)); | |
| DECL_CHAIN (parm) = DECL_ARGUMENTS (decl); | |
| DECL_ARGUMENTS (decl) = parm; | |
| } | |
| DECL_ARGUMENTS (decl) = nreverse (DECL_ARGUMENTS (decl)); | |
| if (class_member_p) | |
| { | |
| if (TREE_CODE (sym_type) == FUNCTION_TYPE) | |
| DECL_STATIC_FUNCTION_P (decl) = 1; | |
| if (sym_flags & GCC_CP_FLAG_VIRTUAL_FUNCTION) | |
| { | |
| DECL_VIRTUAL_P (decl) = 1; | |
| if (sym_flags & GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION) | |
| DECL_PURE_VIRTUAL_P (decl) = 1; | |
| if (sym_flags & GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION) | |
| DECL_FINAL_P (decl) = 1; | |
| } | |
| else | |
| gcc_assert (!(sym_flags & (GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION | |
| | GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION))); | |
| } | |
| else | |
| { | |
| gcc_assert (!(sym_flags & (GCC_CP_FLAG_VIRTUAL_FUNCTION | |
| | GCC_CP_FLAG_PURE_VIRTUAL_FUNCTION | |
| | GCC_CP_FLAG_FINAL_VIRTUAL_FUNCTION))); | |
| gcc_assert (!ctor && !dtor && !assop); | |
| } | |
| if (sym_flags & GCC_CP_FLAG_EXPLICIT_FUNCTION) | |
| DECL_NONCONVERTING_P (decl) = 1; | |
| if (sym_flags & GCC_CP_FLAG_DEFAULTED_FUNCTION) | |
| { | |
| DECL_INITIAL (decl) = ridpointers[(int)RID_DEFAULT]; | |
| DECL_DEFAULTED_FN (decl) = 1; | |
| } | |
| if (sym_flags & GCC_CP_FLAG_DELETED_FUNCTION) | |
| { | |
| // DECL_INITIAL (decl) = ridpointers[(int)RID_DELETE]; | |
| DECL_DELETED_FN (decl) = 1; | |
| DECL_DECLARED_INLINE_P (decl) = 1; | |
| DECL_INITIAL (decl) = error_mark_node; | |
| } | |
| if (ctor) | |
| DECL_CXX_CONSTRUCTOR_P (decl) = 1; | |
| else if (dtor) | |
| DECL_CXX_DESTRUCTOR_P (decl) = 1; | |
| else if ((sym_flags & GCC_CP_FLAG_SPECIAL_FUNCTION) | |
| && opcode != ERROR_MARK) | |
| DECL_OVERLOADED_OPERATOR_CODE_RAW (decl) = ovl_op_mapping[opcode]; | |
| } | |
| else if (RECORD_OR_UNION_CODE_P (code)) | |
| { | |
| decl = build_named_class_type (code, identifier, loc); | |
| tree type = TREE_TYPE (decl); | |
| if (code == RECORD_TYPE | |
| && !(sym_flags & GCC_CP_FLAG_CLASS_IS_STRUCT)) | |
| CLASSTYPE_DECLARED_CLASS (type) = true; | |
| } | |
| else if (class_member_p) | |
| { | |
| decl = build_lang_decl_loc (loc, code, identifier, sym_type); | |
| if (TREE_CODE (decl) == VAR_DECL) | |
| { | |
| DECL_THIS_STATIC (decl) = 1; | |
| // The remainder of this block does the same as: | |
| // set_linkage_for_static_data_member (decl); | |
| TREE_PUBLIC (decl) = 1; | |
| TREE_STATIC (decl) = 1; | |
| DECL_INTERFACE_KNOWN (decl) = 1; | |
| // FIXME: sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE | |
| gcc_assert (!(sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE)); | |
| if (sym_flags & GCC_CP_FLAG_CONSTEXPR_VARIABLE) | |
| DECL_DECLARED_CONSTEXPR_P (decl) = true; | |
| } | |
| } | |
| else | |
| { | |
| decl = build_decl (loc, code, identifier, sym_type); | |
| if (TREE_CODE (decl) == VAR_DECL) | |
| { | |
| // FIXME: sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE | |
| gcc_assert (!(sym_flags & GCC_CP_FLAG_THREAD_LOCAL_VARIABLE)); | |
| if (sym_flags & GCC_CP_FLAG_CONSTEXPR_VARIABLE) | |
| DECL_DECLARED_CONSTEXPR_P (decl) = true; | |
| } | |
| } | |
| TREE_USED (decl) = 1; | |
| TREE_ADDRESSABLE (decl) = 1; | |
| if (class_member_p) | |
| DECL_CONTEXT (decl) = FROB_CONTEXT (current_class_type); | |
| else if (at_namespace_scope_p ()) | |
| DECL_CONTEXT (decl) = FROB_CONTEXT (current_decl_namespace ()); | |
| set_access_flags (decl, acc_flags); | |
| /* If this is the typedef that names an otherwise anonymous type, | |
| propagate the typedef name to the type. In normal compilation, | |
| this is done in grokdeclarator. */ | |
| if (sym_kind == GCC_CP_SYMBOL_TYPEDEF | |
| && !template_decl_p | |
| && DECL_CONTEXT (decl) == TYPE_CONTEXT (sym_type) | |
| && TYPE_UNNAMED_P (sym_type)) | |
| name_unnamed_type (sym_type, decl); | |
| if (sym_kind != GCC_CP_SYMBOL_TYPEDEF | |
| && sym_kind != GCC_CP_SYMBOL_CLASS | |
| && sym_kind != GCC_CP_SYMBOL_UNION | |
| && !template_decl_p && !ctor && !dtor) | |
| { | |
| decl_addr_value value; | |
| DECL_EXTERNAL (decl) = 1; | |
| value.decl = decl; | |
| if (substitution_name != NULL) | |
| { | |
| // If the translator gave us a name without a binding, | |
| // we can just substitute error_mark_node, since we know the | |
| // translator will be reporting an error anyhow. | |
| value.address | |
| = lookup_name (get_identifier (substitution_name)); | |
| if (value.address == NULL_TREE) | |
| value.address = error_mark_node; | |
| } | |
| else if (address) | |
| value.address = build_int_cst_type (ptr_type_node, address); | |
| else | |
| value.address = NULL; | |
| if (value.address) | |
| record_decl_address (ctx, value); | |
| } | |
| if (class_member_p && code == FUNCTION_DECL) | |
| { | |
| if (ctor || dtor) | |
| maybe_retrofit_in_chrg (decl); | |
| grok_special_member_properties (decl); | |
| } | |
| if (template_decl_p) | |
| { | |
| if (RECORD_OR_UNION_CODE_P (code)) | |
| safe_pushtag (identifier, TREE_TYPE (decl)); | |
| else | |
| decl = safe_push_template_decl (decl); | |
| tree tdecl = NULL_TREE; | |
| if (class_member_p) | |
| tdecl = finish_member_template_decl (decl); | |
| end_template_decl (); | |
| /* We only support one level of templates, because we only | |
| support declaring generics; actual definitions are only of | |
| specializations. */ | |
| gcc_assert (!template_parm_scope_p ()); | |
| if (class_member_p) | |
| finish_member_declaration (tdecl); | |
| } | |
| else if (RECORD_OR_UNION_CODE_P (code)) | |
| safe_pushtag (identifier, TREE_TYPE (decl)); | |
| else if (class_member_p) | |
| finish_member_declaration (decl); | |
| else | |
| decl = safe_pushdecl (decl); | |
| if ((ctor || dtor) | |
| /* Don't crash after a duplicate declaration of a cdtor. */ | |
| && TYPE_FIELDS (current_class_type) == decl) | |
| { | |
| /* ctors and dtors clones are chained after DECL. | |
| However, we create the clones before TYPE_METHODS is | |
| reversed. We test for cloned methods after reversal, | |
| however, and the test requires the clones to follow | |
| DECL. So, we reverse the chain of clones now, so | |
| that it will come out in the right order after | |
| reversal. */ | |
| tree save = DECL_CHAIN (decl); | |
| DECL_CHAIN (decl) = NULL_TREE; | |
| clone_cdtor (decl, /*update_methods=*/true); | |
| gcc_assert (TYPE_FIELDS (current_class_type) == decl); | |
| TYPE_FIELDS (current_class_type) | |
| = nreverse (TYPE_FIELDS (current_class_type)); | |
| DECL_CHAIN (decl) = save; | |
| } | |
| rest_of_decl_compilation (decl, toplevel_bindings_p (), 0); | |
| return convert_out (ctx->preserve (decl)); | |
| } | |
| gcc_decl | |
| plugin_define_cdtor_clone (cc1_plugin::connection *self, | |
| const char *name, | |
| gcc_decl cdtor_in, | |
| gcc_address address) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree decl = convert_in (cdtor_in); | |
| bool ctor = false; | |
| bool dtor = false; | |
| tree identifier; | |
| switch (CHARS2 (name[0], name[1])) | |
| { | |
| case CHARS2 ('C', '1'): // in-charge constructor | |
| identifier = complete_ctor_identifier; | |
| ctor = true; | |
| break; | |
| case CHARS2 ('C', '2'): // not-in-charge constructor | |
| identifier = base_ctor_identifier; | |
| ctor = true; | |
| break; | |
| case CHARS2 ('C', '4'): | |
| identifier = ctor_identifier; // unified constructor | |
| ctor = true; | |
| break; | |
| case CHARS2 ('D', '0'): // deleting destructor | |
| identifier = deleting_dtor_identifier; | |
| dtor = true; | |
| break; | |
| case CHARS2 ('D', '1'): // in-charge destructor | |
| identifier = complete_dtor_identifier; | |
| dtor = true; | |
| break; | |
| case CHARS2 ('D', '2'): // not-in-charge destructor | |
| identifier = base_dtor_identifier; | |
| dtor = true; | |
| break; | |
| case CHARS2 ('D', '4'): | |
| identifier = dtor_identifier; // unified destructor | |
| dtor = true; | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| gcc_assert (!ctor != !dtor); | |
| gcc_assert (ctor | |
| ? (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl) | |
| && DECL_NAME (decl) == ctor_identifier) | |
| : (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl) | |
| && DECL_NAME (decl) == dtor_identifier)); | |
| while (decl && DECL_NAME (decl) != identifier) | |
| { | |
| decl = DECL_CHAIN (decl); | |
| if (decl && !DECL_CLONED_FUNCTION_P (decl)) | |
| decl = NULL_TREE; | |
| } | |
| gcc_assert (decl); | |
| record_decl_address (ctx, build_decl_addr_value (decl, address)); | |
| return convert_out (decl); | |
| } | |
| int | |
| plugin_add_friend (cc1_plugin::connection * /* self */, | |
| gcc_decl decl_in, | |
| gcc_type type_in) | |
| { | |
| tree decl = convert_in (decl_in); | |
| tree type = convert_in (type_in); | |
| gcc_assert (type || at_class_scope_p ()); | |
| if (!type) | |
| type = current_class_type; | |
| else | |
| gcc_assert (TREE_CODE (type) == RECORD_TYPE); | |
| if (TYPE_P (decl)) | |
| make_friend_class (type, TREE_TYPE (decl), true); | |
| else | |
| { | |
| DECL_UNIQUE_FRIEND_P (decl) = true; | |
| add_friend (type, decl, true); | |
| } | |
| return 1; | |
| } | |
| gcc_type | |
| plugin_build_pointer_type (cc1_plugin::connection *, | |
| gcc_type base_type) | |
| { | |
| // No need to preserve a pointer type as the base type is preserved. | |
| return convert_out (build_pointer_type (convert_in (base_type))); | |
| } | |
| gcc_type | |
| plugin_build_reference_type (cc1_plugin::connection *, | |
| gcc_type base_type_in, | |
| enum gcc_cp_ref_qualifiers rquals) | |
| { | |
| bool rval; | |
| switch (rquals) | |
| { | |
| case GCC_CP_REF_QUAL_LVALUE: | |
| rval = false; | |
| break; | |
| case GCC_CP_REF_QUAL_RVALUE: | |
| rval = true; | |
| break; | |
| case GCC_CP_REF_QUAL_NONE: | |
| default: | |
| gcc_unreachable (); | |
| } | |
| tree rtype = cp_build_reference_type (convert_in (base_type_in), rval); | |
| return convert_out (rtype); | |
| } | |
| static tree | |
| start_class_def (tree type, | |
| const gcc_vbase_array *base_classes) | |
| { | |
| tree bases = NULL; | |
| if (base_classes) | |
| { | |
| for (int i = 0; i < base_classes->n_elements; i++) | |
| { | |
| tree access; | |
| gcc_assert ((base_classes->flags[i] & GCC_CP_SYMBOL_MASK) | |
| == GCC_CP_SYMBOL_BASECLASS); | |
| switch (base_classes->flags[i] & GCC_CP_ACCESS_MASK) | |
| { | |
| case GCC_CP_ACCESS_PRIVATE: | |
| access = ridpointers[(int)RID_PRIVATE]; | |
| break; | |
| case GCC_CP_ACCESS_PROTECTED: | |
| access = ridpointers[(int)RID_PROTECTED]; | |
| break; | |
| case GCC_CP_ACCESS_PUBLIC: | |
| access = ridpointers[(int)RID_PUBLIC]; | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| tree base = finish_base_specifier | |
| (convert_in (base_classes->elements[i]), access, | |
| (base_classes->flags[i] & GCC_CP_FLAG_BASECLASS_VIRTUAL) != 0, | |
| NULL_TREE); | |
| TREE_CHAIN (base) = bases; | |
| bases = base; | |
| } | |
| bases = nreverse (bases); | |
| } | |
| xref_basetypes (type, bases); | |
| begin_class_definition (type); | |
| return type; | |
| } | |
| gcc_type | |
| plugin_start_class_type (cc1_plugin::connection *self, | |
| gcc_decl typedecl_in, | |
| const gcc_vbase_array *base_classes, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| tree typedecl = convert_in (typedecl_in); | |
| tree type = TREE_TYPE (typedecl); | |
| gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (type))); | |
| gcc_assert (!COMPLETE_TYPE_P (type)); | |
| DECL_SOURCE_LOCATION (typedecl) = loc; | |
| tree result = start_class_def (type, base_classes); | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_type | |
| plugin_start_closure_class_type (cc1_plugin::connection *self, | |
| int discriminator, | |
| gcc_decl extra_scope_in, | |
| enum gcc_cp_symbol_kind flags, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree extra_scope = convert_in (extra_scope_in); | |
| gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_LAMBDA_CLOSURE); | |
| gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK))) == 0); | |
| gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !at_class_scope_p ()); | |
| /* See at_fake_function_scope_p. */ | |
| gcc_assert (!at_function_scope_p ()); | |
| if (extra_scope) | |
| { | |
| if (TREE_CODE (extra_scope) == PARM_DECL) | |
| { | |
| gcc_assert (at_fake_function_scope_p ()); | |
| /* Check that the given extra_scope is one of the parameters of | |
| the current function. */ | |
| for (tree parm = DECL_ARGUMENTS (current_function_decl); | |
| ; parm = DECL_CHAIN (parm)) | |
| { | |
| gcc_assert (parm); | |
| if (parm == extra_scope) | |
| break; | |
| } | |
| } | |
| else if (TREE_CODE (extra_scope) == FIELD_DECL) | |
| { | |
| gcc_assert (at_class_scope_p ()); | |
| gcc_assert (DECL_CONTEXT (extra_scope) == current_class_type); | |
| } | |
| else | |
| /* FIXME: does this ever really occur? */ | |
| gcc_assert (TREE_CODE (extra_scope) == VAR_DECL); | |
| } | |
| tree lambda_expr = build_lambda_expr (); | |
| LAMBDA_EXPR_LOCATION (lambda_expr) = ctx->get_location_t (filename, | |
| line_number); | |
| tree type = begin_lambda_type (lambda_expr); | |
| /* Instead of calling record_lambda_scope, do this: */ | |
| LAMBDA_EXPR_EXTRA_SCOPE (lambda_expr) = extra_scope; | |
| LAMBDA_EXPR_SCOPE_ONLY_DISCRIMINATOR (lambda_expr) = discriminator; | |
| LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda_expr) = discriminator; | |
| tree decl = TYPE_NAME (type); | |
| determine_visibility (decl); | |
| set_access_flags (decl, flags); | |
| return convert_out (ctx->preserve (type)); | |
| } | |
| gcc_expr | |
| plugin_build_lambda_expr (cc1_plugin::connection *self, | |
| gcc_type closure_type_in) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree closure_type = convert_in (closure_type_in); | |
| gcc_assert (LAMBDA_TYPE_P (closure_type)); | |
| tree lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure_type); | |
| tree lambda_object = build_lambda_object (lambda_expr); | |
| return convert_out (ctx->preserve (lambda_object)); | |
| } | |
| gcc_decl | |
| plugin_build_field (cc1_plugin::connection *, | |
| const char *field_name, | |
| gcc_type field_type_in, | |
| enum gcc_cp_symbol_kind flags, | |
| unsigned long bitsize, | |
| unsigned long bitpos) | |
| { | |
| tree record_or_union_type = current_class_type; | |
| tree field_type = convert_in (field_type_in); | |
| gcc_assert (at_class_scope_p ()); | |
| gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type))); | |
| gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_FIELD); | |
| gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK | |
| | GCC_CP_FLAG_MASK_FIELD))) == 0); | |
| gcc_assert ((flags & GCC_CP_ACCESS_MASK)); | |
| /* Note that gdb does not preserve the location of field decls, so | |
| we can't provide a decent location here. */ | |
| tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL, | |
| get_identifier (field_name), field_type); | |
| DECL_FIELD_CONTEXT (decl) = record_or_union_type; | |
| set_access_flags (decl, flags); | |
| if ((flags & GCC_CP_FLAG_FIELD_MUTABLE) != 0) | |
| DECL_MUTABLE_P (decl) = 1; | |
| if (TREE_CODE (field_type) == INTEGER_TYPE | |
| && TYPE_PRECISION (field_type) != bitsize) | |
| { | |
| DECL_BIT_FIELD_TYPE (decl) = field_type; | |
| TREE_TYPE (decl) | |
| = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type)); | |
| } | |
| SET_DECL_MODE (decl, TYPE_MODE (TREE_TYPE (decl))); | |
| // There's no way to recover this from DWARF. | |
| SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node)); | |
| tree pos = bitsize_int (bitpos); | |
| pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl), | |
| DECL_OFFSET_ALIGN (decl), pos); | |
| DECL_SIZE (decl) = bitsize_int (bitsize); | |
| DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1) | |
| / BITS_PER_UNIT); | |
| DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type); | |
| TYPE_FIELDS (record_or_union_type) = decl; | |
| return convert_out (decl); | |
| } | |
| int | |
| plugin_finish_class_type (cc1_plugin::connection *, | |
| unsigned long size_in_bytes) | |
| { | |
| tree record_or_union_type = current_class_type; | |
| gcc_assert (RECORD_OR_UNION_CODE_P (TREE_CODE (record_or_union_type))); | |
| finish_struct (record_or_union_type, NULL); | |
| gcc_assert (compare_tree_int (TYPE_SIZE_UNIT (record_or_union_type), | |
| size_in_bytes) == 0); | |
| return 1; | |
| } | |
| gcc_type | |
| plugin_start_enum_type (cc1_plugin::connection *self, | |
| const char *name, | |
| gcc_type underlying_int_type_in, | |
| enum gcc_cp_symbol_kind flags, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree underlying_int_type = convert_in (underlying_int_type_in); | |
| gcc_assert ((flags & GCC_CP_SYMBOL_MASK) == GCC_CP_SYMBOL_ENUM); | |
| gcc_assert ((flags & (~(GCC_CP_SYMBOL_MASK | GCC_CP_ACCESS_MASK | |
| | GCC_CP_FLAG_MASK_ENUM))) == 0); | |
| gcc_assert (!(flags & GCC_CP_ACCESS_MASK) == !at_class_scope_p ()); | |
| if (underlying_int_type == error_mark_node) | |
| return convert_out (error_mark_node); | |
| bool is_new_type = false; | |
| tree id = name ? get_identifier (name) : make_anon_name (); | |
| tree type = start_enum (id, NULL_TREE, | |
| underlying_int_type, | |
| /* attributes = */ NULL_TREE, | |
| !!(flags & GCC_CP_FLAG_ENUM_SCOPED), &is_new_type); | |
| gcc_assert (is_new_type); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| tree type_decl = TYPE_NAME (type); | |
| DECL_SOURCE_LOCATION (type_decl) = loc; | |
| SET_OPAQUE_ENUM_P (type, false); | |
| set_access_flags (type_decl, flags); | |
| return convert_out (ctx->preserve (type)); | |
| } | |
| gcc_decl | |
| plugin_build_enum_constant (cc1_plugin::connection *, | |
| gcc_type enum_type_in, | |
| const char *name, | |
| unsigned long value) | |
| { | |
| tree enum_type = convert_in (enum_type_in); | |
| gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE); | |
| build_enumerator (get_identifier (name), build_int_cst (enum_type, value), | |
| enum_type, NULL_TREE, BUILTINS_LOCATION); | |
| return convert_out (TREE_VALUE (TYPE_VALUES (enum_type))); | |
| } | |
| int | |
| plugin_finish_enum_type (cc1_plugin::connection *, | |
| gcc_type enum_type_in) | |
| { | |
| tree enum_type = convert_in (enum_type_in); | |
| finish_enum_value_list (enum_type); | |
| finish_enum (enum_type); | |
| return 1; | |
| } | |
| gcc_type | |
| plugin_build_function_type (cc1_plugin::connection *self, | |
| gcc_type return_type_in, | |
| const struct gcc_type_array *argument_types_in, | |
| int is_varargs) | |
| { | |
| tree return_type = convert_in (return_type_in); | |
| tree result; | |
| std::vector<tree> argument_types (argument_types_in->n_elements); | |
| for (int i = 0; i < argument_types_in->n_elements; ++i) | |
| argument_types[i] = convert_in (argument_types_in->elements[i]); | |
| if (is_varargs) | |
| result = build_varargs_function_type_array (return_type, | |
| argument_types_in->n_elements, | |
| argument_types.data ()); | |
| else | |
| result = build_function_type_array (return_type, | |
| argument_types_in->n_elements, | |
| argument_types.data ()); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| #if 0 | |
| gcc_type | |
| plugin_add_function_default_args (cc1_plugin::connection *self, | |
| gcc_type function_type_in, | |
| const struct gcc_cp_function_args *defaults) | |
| { | |
| tree function_type = convert_in (function_type_in); | |
| gcc_assert (TREE_CODE (function_type) == FUNCTION_TYPE); | |
| if (!defaults || !defaults->n_elements) | |
| return function_type_in; | |
| tree pargs = TYPE_ARG_TYPES (function_type); | |
| tree nargs = NULL_TREE; | |
| /* Build a reversed copy of the list of default-less arguments in | |
| NARGS. At the end of the loop, PARGS will point to the end of | |
| the argument list, or to the first argument that had a default | |
| value. */ | |
| while (pargs && TREE_VALUE (pargs) != void_list_node | |
| && !TREE_PURPOSE (pargs)) | |
| { | |
| nargs = tree_cons (NULL_TREE, TREE_VALUE (pargs), nargs); | |
| pargs = TREE_CHAIN (pargs); | |
| } | |
| /* Set the defaults in the now-leading NARGS, taking into account | |
| that NARGS is reversed but DEFAULTS->elements isn't. */ | |
| tree ndargs = nargs; | |
| int i = defaults->n_elements; | |
| while (i--) | |
| { | |
| gcc_assert (ndargs); | |
| tree deflt = convert_in (defaults->elements[i]); | |
| if (!deflt) | |
| deflt = error_mark_node; | |
| TREE_PURPOSE (ndargs) = deflt; | |
| ndargs = TREE_CHAIN (ndargs); | |
| } | |
| /* Finally, reverse NARGS, and append the remaining PARGS that | |
| already had defaults. */ | |
| nargs = nreverse (nargs); | |
| nargs = chainon (nargs, pargs); | |
| tree result = build_function_type (TREE_TYPE (function_type), nargs); | |
| /* Copy exceptions, attributes and whatnot. */ | |
| result = build_exception_variant (result, | |
| TYPE_RAISES_EXCEPTIONS (function_type)); | |
| result = cp_build_type_attribute_variant (result, | |
| TYPE_ATTRIBUTES (function_type)); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| int | |
| plugin_set_deferred_function_default_args (cc1_plugin::connection *, | |
| gcc_decl function_in, | |
| const struct gcc_cp_function_args | |
| *defaults) | |
| { | |
| tree function = convert_in (function_in); | |
| gcc_assert (TREE_CODE (function) == FUNCTION_DECL); | |
| if (!defaults || !defaults->n_elements) | |
| return 1; | |
| tree arg = FUNCTION_FIRST_USER_PARMTYPE (function); | |
| for (int i = 0; i < defaults->n_elements; i++) | |
| { | |
| while (arg && TREE_PURPOSE (arg) != error_mark_node) | |
| arg = TREE_CHAIN (arg); | |
| if (!arg) | |
| return 0; | |
| TREE_PURPOSE (arg) = convert_in (defaults->elements[i]); | |
| arg = TREE_CHAIN (arg); | |
| } | |
| return 1; | |
| } | |
| #endif | |
| gcc_decl | |
| plugin_get_function_parameter_decl (cc1_plugin::connection *, | |
| gcc_decl function_in, | |
| int index) | |
| { | |
| tree function = convert_in (function_in); | |
| gcc_assert (TREE_CODE (function) == FUNCTION_DECL); | |
| if (index == -1) | |
| { | |
| gcc_assert (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE); | |
| return convert_out (DECL_ARGUMENTS (function)); | |
| } | |
| gcc_assert (index >= 0); | |
| tree args = FUNCTION_FIRST_USER_PARM (function); | |
| for (int i = 0; args && i < index; i++) | |
| args = DECL_CHAIN (args); | |
| return convert_out (args); | |
| } | |
| gcc_type | |
| plugin_build_exception_spec_variant (cc1_plugin::connection *self, | |
| gcc_type function_type_in, | |
| const struct gcc_type_array *except_types_in) | |
| { | |
| tree function_type = convert_in (function_type_in); | |
| tree except_types = NULL_TREE; | |
| if (!except_types_in) | |
| except_types = noexcept_false_spec; | |
| else if (!except_types_in->n_elements) | |
| except_types = empty_except_spec; | |
| else | |
| for (int i = 0; i < except_types_in->n_elements; i++) | |
| except_types = add_exception_specifier (except_types, | |
| convert_in | |
| (except_types_in->elements[i]), | |
| 0); | |
| function_type = build_exception_variant (function_type, | |
| except_types); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (function_type)); | |
| } | |
| gcc_type | |
| plugin_build_method_type (cc1_plugin::connection *self, | |
| gcc_type class_type_in, | |
| gcc_type func_type_in, | |
| enum gcc_cp_qualifiers quals_in, | |
| enum gcc_cp_ref_qualifiers rquals_in) | |
| { | |
| tree class_type = convert_in (class_type_in); | |
| tree func_type = convert_in (func_type_in); | |
| cp_cv_quals quals = 0; | |
| cp_ref_qualifier rquals; | |
| if ((quals_in & GCC_CP_QUALIFIER_CONST) != 0) | |
| quals |= TYPE_QUAL_CONST; | |
| if ((quals_in & GCC_CP_QUALIFIER_VOLATILE) != 0) | |
| quals |= TYPE_QUAL_VOLATILE; | |
| gcc_assert ((quals_in & GCC_CP_QUALIFIER_RESTRICT) == 0); | |
| switch (rquals_in) | |
| { | |
| case GCC_CP_REF_QUAL_NONE: | |
| rquals = REF_QUAL_NONE; | |
| break; | |
| case GCC_CP_REF_QUAL_LVALUE: | |
| rquals = REF_QUAL_LVALUE; | |
| break; | |
| case GCC_CP_REF_QUAL_RVALUE: | |
| rquals = REF_QUAL_RVALUE; | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| tree method_type = class_type | |
| ? build_memfn_type (func_type, class_type, quals, rquals) | |
| : apply_memfn_quals (func_type, quals, rquals); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (method_type)); | |
| } | |
| gcc_type | |
| plugin_build_pointer_to_member_type (cc1_plugin::connection *self, | |
| gcc_type class_type_in, | |
| gcc_type member_type_in) | |
| { | |
| tree class_type = convert_in (class_type_in); | |
| tree member_type = convert_in (member_type_in); | |
| tree memptr_type = build_ptrmem_type (class_type, member_type); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (memptr_type)); | |
| } | |
| int | |
| plugin_start_template_decl (cc1_plugin::connection *) | |
| { | |
| begin_template_parm_list (); | |
| TP_PARM_LIST = NULL_TREE; | |
| return 1; | |
| } | |
| gcc_decl | |
| plugin_get_type_decl (cc1_plugin::connection *, | |
| gcc_type type_in) | |
| { | |
| tree type = convert_in (type_in); | |
| tree name = TYPE_NAME (type); | |
| gcc_assert (name); | |
| return convert_out (name); | |
| } | |
| gcc_type | |
| plugin_get_decl_type (cc1_plugin::connection *, | |
| gcc_decl decl_in) | |
| { | |
| tree decl = convert_in (decl_in); | |
| tree type = TREE_TYPE (decl); | |
| gcc_assert (type); | |
| return convert_out (type); | |
| } | |
| gcc_type | |
| plugin_build_type_template_parameter (cc1_plugin::connection *self, | |
| const char *id, | |
| int /* bool */ pack_p, | |
| gcc_type default_type, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| gcc_assert (template_parm_scope_p ()); | |
| tree parm = finish_template_type_parm (class_type_node, get_identifier (id)); | |
| parm = build_tree_list (convert_in (default_type), parm); | |
| gcc_assert (!(pack_p && default_type)); | |
| /* Create a type and a decl for the type parm, and add the decl to | |
| TP_PARM_LIST. */ | |
| TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm, | |
| /* is_non_type = */ false, pack_p); | |
| /* Locate the decl of the newly-added, processed template parm. */ | |
| parm = TREE_VALUE (tree_last (TP_PARM_LIST)); | |
| /* Return its type. */ | |
| return convert_out (ctx->preserve (TREE_TYPE (parm))); | |
| } | |
| gcc_utempl | |
| plugin_build_template_template_parameter (cc1_plugin::connection *self, | |
| const char *id, | |
| int /* bool */ pack_p, | |
| gcc_utempl default_templ, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| gcc_assert (template_parm_scope_p ()); | |
| /* Finish the template parm list that started this template parm. */ | |
| end_template_parm_list (TP_PARM_LIST); | |
| gcc_assert (template_parm_scope_p ()); | |
| tree parm = finish_template_template_parm (class_type_node, | |
| get_identifier (id)); | |
| parm = build_tree_list (convert_in (default_templ), parm); | |
| gcc_assert (!(pack_p && default_templ)); | |
| /* Create a type and a decl for the template parm, and add the decl | |
| to TP_PARM_LIST. */ | |
| TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm, | |
| /* is_non_type = */ false, pack_p); | |
| /* Locate the decl of the newly-added, processed template parm. */ | |
| parm = TREE_VALUE (tree_last (TP_PARM_LIST)); | |
| return convert_out (ctx->preserve (parm)); | |
| } | |
| gcc_decl | |
| plugin_build_value_template_parameter (cc1_plugin::connection *self, | |
| gcc_type type, | |
| const char *id, | |
| gcc_expr default_value, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| gcc_assert (template_parm_scope_p ()); | |
| cp_declarator declarator; | |
| memset (&declarator, 0, sizeof (declarator)); | |
| // &declarator = make_id_declarator (NULL, get_identifier (id), sfk_none): | |
| declarator.kind = cdk_id; | |
| declarator.u.id.qualifying_scope = NULL; | |
| declarator.u.id.unqualified_name = get_identifier (id); | |
| declarator.u.id.sfk = sfk_none; | |
| cp_decl_specifier_seq declspec; | |
| memset (&declspec, 0, sizeof (declspec)); | |
| // cp_parser_set_decl_spec_type (&declspec, convert_in (type), -token-, false): | |
| declspec.any_specifiers_p = declspec.any_type_specifiers_p = true; | |
| declspec.type = convert_in (type); | |
| declspec.locations[ds_type_spec] = loc; | |
| tree parm = grokdeclarator (&declarator, &declspec, TPARM, 0, 0); | |
| parm = build_tree_list (convert_in (default_value), parm); | |
| /* Create a type and a decl for the template parm, and add the decl | |
| to TP_PARM_LIST. */ | |
| TP_PARM_LIST = process_template_parm (TP_PARM_LIST, loc, parm, | |
| /* is_non_type = */ true, false); | |
| /* Locate the decl of the newly-added, processed template parm. */ | |
| parm = TREE_VALUE (tree_last (TP_PARM_LIST)); | |
| return convert_out (ctx->preserve (parm)); | |
| } | |
| static tree | |
| targlist (const gcc_cp_template_args *targs) | |
| { | |
| int n = targs->n_elements; | |
| tree vec = make_tree_vec (n); | |
| while (n--) | |
| { | |
| switch (targs->kinds[n]) | |
| { | |
| case GCC_CP_TPARG_VALUE: | |
| TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].value); | |
| break; | |
| case GCC_CP_TPARG_CLASS: | |
| TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].type); | |
| break; | |
| case GCC_CP_TPARG_TEMPL: | |
| TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].templ); | |
| break; | |
| case GCC_CP_TPARG_PACK: | |
| TREE_VEC_ELT (vec, n) = convert_in (targs->elements[n].pack); | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| } | |
| return vec; | |
| } | |
| gcc_type | |
| plugin_build_dependent_typename (cc1_plugin::connection *self, | |
| gcc_type enclosing_type, | |
| const char *id, | |
| const gcc_cp_template_args *targs) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree type = convert_in (enclosing_type); | |
| tree name = get_identifier (id); | |
| if (targs) | |
| name = build_min_nt_loc (/*loc=*/0, TEMPLATE_ID_EXPR, | |
| name, targlist (targs)); | |
| tree res = make_typename_type (type, name, typename_type, | |
| /*complain=*/tf_error); | |
| return convert_out (ctx->preserve (res)); | |
| } | |
| gcc_utempl | |
| plugin_build_dependent_class_template (cc1_plugin::connection *self, | |
| gcc_type enclosing_type, | |
| const char *id) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree type = convert_in (enclosing_type); | |
| tree name = get_identifier (id); | |
| tree res = make_unbound_class_template (type, name, NULL_TREE, | |
| /*complain=*/tf_error); | |
| return convert_out (ctx->preserve (res)); | |
| } | |
| gcc_type | |
| plugin_build_dependent_type_template_id (cc1_plugin::connection *self, | |
| gcc_utempl template_decl, | |
| const gcc_cp_template_args *targs) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree type = convert_in (template_decl); | |
| tree decl = finish_template_type (type, targlist (targs), | |
| /*entering_scope=*/false); | |
| return convert_out (ctx->preserve (TREE_TYPE (decl))); | |
| } | |
| gcc_expr | |
| plugin_build_dependent_expr (cc1_plugin::connection *self, | |
| gcc_decl enclosing_scope, | |
| enum gcc_cp_symbol_kind flags, | |
| const char *name, | |
| gcc_type conv_type_in, | |
| const gcc_cp_template_args *targs) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree scope = convert_in (enclosing_scope); | |
| tree conv_type = convert_in (conv_type_in); | |
| tree identifier; | |
| if (TREE_CODE (scope) != NAMESPACE_DECL) | |
| { | |
| tree type = TREE_TYPE (scope); | |
| gcc_assert (TYPE_NAME (type) == scope); | |
| scope = type; | |
| } | |
| if (flags == (GCC_CP_SYMBOL_FUNCTION | GCC_CP_FLAG_SPECIAL_FUNCTION)) | |
| { | |
| bool assop = false, convop = false; | |
| tree_code opcode = ERROR_MARK; | |
| switch (CHARS2 (name[0], name[1])) | |
| { | |
| case CHARS2 ('C', 0x0): // ctor base declaration | |
| case CHARS2 ('C', ' '): | |
| case CHARS2 ('C', '1'): | |
| case CHARS2 ('C', '2'): | |
| case CHARS2 ('C', '4'): | |
| identifier = ctor_identifier; | |
| break; | |
| case CHARS2 ('D', 0x0): // dtor base declaration | |
| case CHARS2 ('D', ' '): | |
| case CHARS2 ('D', '0'): | |
| case CHARS2 ('D', '1'): | |
| case CHARS2 ('D', '2'): | |
| case CHARS2 ('D', '4'): | |
| gcc_assert (!targs); | |
| identifier = dtor_identifier; | |
| break; | |
| case CHARS2 ('n', 'w'): // operator new | |
| opcode = NEW_EXPR; | |
| break; | |
| case CHARS2 ('n', 'a'): // operator new[] | |
| opcode = VEC_NEW_EXPR; | |
| break; | |
| case CHARS2 ('d', 'l'): // operator delete | |
| opcode = DELETE_EXPR; | |
| break; | |
| case CHARS2 ('d', 'a'): // operator delete[] | |
| opcode = VEC_DELETE_EXPR; | |
| break; | |
| case CHARS2 ('p', 's'): // operator + (unary) | |
| opcode = PLUS_EXPR; | |
| break; | |
| case CHARS2 ('n', 'g'): // operator - (unary) | |
| opcode = MINUS_EXPR; | |
| break; | |
| case CHARS2 ('a', 'd'): // operator & (unary) | |
| opcode = BIT_AND_EXPR; | |
| break; | |
| case CHARS2 ('d', 'e'): // operator * (unary) | |
| opcode = MULT_EXPR; | |
| break; | |
| case CHARS2 ('c', 'o'): // operator ~ | |
| opcode = BIT_NOT_EXPR; | |
| break; | |
| case CHARS2 ('p', 'l'): // operator + | |
| opcode = PLUS_EXPR; | |
| break; | |
| case CHARS2 ('m', 'i'): // operator - | |
| opcode = MINUS_EXPR; | |
| break; | |
| case CHARS2 ('m', 'l'): // operator * | |
| opcode = MULT_EXPR; | |
| break; | |
| case CHARS2 ('d', 'v'): // operator / | |
| opcode = TRUNC_DIV_EXPR; | |
| break; | |
| case CHARS2 ('r', 'm'): // operator % | |
| opcode = TRUNC_MOD_EXPR; | |
| break; | |
| case CHARS2 ('a', 'n'): // operator & | |
| opcode = BIT_AND_EXPR; | |
| break; | |
| case CHARS2 ('o', 'r'): // operator | | |
| opcode = BIT_IOR_EXPR; | |
| break; | |
| case CHARS2 ('e', 'o'): // operator ^ | |
| opcode = BIT_XOR_EXPR; | |
| break; | |
| case CHARS2 ('a', 'S'): // operator = | |
| opcode = NOP_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('p', 'L'): // operator += | |
| opcode = PLUS_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('m', 'I'): // operator -= | |
| opcode = MINUS_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('m', 'L'): // operator *= | |
| opcode = MULT_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('d', 'V'): // operator /= | |
| opcode = TRUNC_DIV_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('r', 'M'): // operator %= | |
| opcode = TRUNC_MOD_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('a', 'N'): // operator &= | |
| opcode = BIT_AND_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('o', 'R'): // operator |= | |
| opcode = BIT_IOR_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('e', 'O'): // operator ^= | |
| opcode = BIT_XOR_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('l', 's'): // operator << | |
| opcode = LSHIFT_EXPR; | |
| break; | |
| case CHARS2 ('r', 's'): // operator >> | |
| opcode = RSHIFT_EXPR; | |
| break; | |
| case CHARS2 ('l', 'S'): // operator <<= | |
| opcode = LSHIFT_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('r', 'S'): // operator >>= | |
| opcode = RSHIFT_EXPR; | |
| assop = true; | |
| break; | |
| case CHARS2 ('e', 'q'): // operator == | |
| opcode = EQ_EXPR; | |
| break; | |
| case CHARS2 ('n', 'e'): // operator != | |
| opcode = NE_EXPR; | |
| break; | |
| case CHARS2 ('l', 't'): // operator < | |
| opcode = LT_EXPR; | |
| break; | |
| case CHARS2 ('g', 't'): // operator > | |
| opcode = GT_EXPR; | |
| break; | |
| case CHARS2 ('l', 'e'): // operator <= | |
| opcode = LE_EXPR; | |
| break; | |
| case CHARS2 ('g', 'e'): // operator >= | |
| opcode = GE_EXPR; | |
| break; | |
| case CHARS2 ('n', 't'): // operator ! | |
| opcode = TRUTH_NOT_EXPR; | |
| break; | |
| case CHARS2 ('a', 'a'): // operator && | |
| opcode = TRUTH_ANDIF_EXPR; | |
| break; | |
| case CHARS2 ('o', 'o'): // operator || | |
| opcode = TRUTH_ORIF_EXPR; | |
| break; | |
| case CHARS2 ('p', 'p'): // operator ++ | |
| opcode = POSTINCREMENT_EXPR; | |
| break; | |
| case CHARS2 ('m', 'm'): // operator -- | |
| opcode = PREDECREMENT_EXPR; | |
| break; | |
| case CHARS2 ('c', 'm'): // operator , | |
| opcode = COMPOUND_EXPR; | |
| break; | |
| case CHARS2 ('p', 'm'): // operator ->* | |
| opcode = MEMBER_REF; | |
| break; | |
| case CHARS2 ('p', 't'): // operator -> | |
| opcode = COMPONENT_REF; | |
| break; | |
| case CHARS2 ('c', 'l'): // operator () | |
| opcode = CALL_EXPR; | |
| break; | |
| case CHARS2 ('i', 'x'): // operator [] | |
| opcode = ARRAY_REF; | |
| break; | |
| case CHARS2 ('c', 'v'): // operator <T> (conversion operator) | |
| convop = true; | |
| identifier = make_conv_op_name (conv_type); | |
| break; | |
| // C++11-only: | |
| case CHARS2 ('l', 'i'): // operator "" <id> | |
| { | |
| char *id = (char *)name + 2; | |
| bool freeid = false; | |
| if (*id >= '0' && *id <= '9') | |
| { | |
| unsigned len = 0; | |
| do | |
| { | |
| len *= 10; | |
| len += id[0] - '0'; | |
| id++; | |
| } | |
| while (*id && *id >= '0' && *id <= '9'); | |
| id = xstrndup (id, len); | |
| freeid = true; | |
| } | |
| identifier = cp_literal_operator_id (id); | |
| if (freeid) | |
| free (id); | |
| } | |
| break; | |
| case CHARS2 ('q', 'u'): // ternary operator, not overloadable. | |
| default: | |
| gcc_unreachable (); | |
| } | |
| gcc_assert (convop || !conv_type); | |
| if (opcode != ERROR_MARK) | |
| identifier = ovl_op_identifier (assop, opcode); | |
| gcc_assert (identifier); | |
| } | |
| else | |
| { | |
| gcc_assert (flags == GCC_CP_SYMBOL_MASK); | |
| gcc_assert (!conv_type); | |
| identifier = get_identifier (name); | |
| } | |
| tree res = identifier; | |
| if (!scope) | |
| res = lookup_name (res, LOOK_where::BLOCK_NAMESPACE); | |
| else if (!TYPE_P (scope) || !dependent_scope_p (scope)) | |
| { | |
| res = lookup_qualified_name (scope, res, LOOK_want::NORMAL, true); | |
| /* We've already resolved the name in the scope, so skip the | |
| build_qualified_name call below. */ | |
| scope = NULL; | |
| } | |
| if (targs) | |
| res = lookup_template_function (res, targlist (targs)); | |
| if (scope) | |
| res = build_qualified_name (NULL_TREE, scope, res, !!targs); | |
| return convert_out (ctx->preserve (res)); | |
| } | |
| gcc_expr | |
| plugin_build_literal_expr (cc1_plugin::connection *self, | |
| gcc_type type, unsigned long value) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree t = convert_in (type); | |
| tree val = build_int_cst_type (t, (unsigned HOST_WIDE_INT) value); | |
| return convert_out (ctx->preserve (val)); | |
| } | |
| gcc_expr | |
| plugin_build_decl_expr (cc1_plugin::connection *self, | |
| gcc_decl decl_in, | |
| int qualified_p) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree decl = convert_in (decl_in); | |
| gcc_assert (DECL_P (decl)); | |
| tree result = decl; | |
| if (qualified_p) | |
| { | |
| gcc_assert (DECL_CLASS_SCOPE_P (decl)); | |
| result = build_offset_ref (DECL_CONTEXT (decl), decl, | |
| /*address_p=*/true, tf_error); | |
| } | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_expr | |
| plugin_build_unary_expr (cc1_plugin::connection *self, | |
| const char *unary_op, | |
| gcc_expr operand) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree op0 = convert_in (operand); | |
| tree_code opcode = ERROR_MARK; | |
| bool global_scope_p = false; | |
| once_more: | |
| switch (CHARS2 (unary_op[0], unary_op[1])) | |
| { | |
| case CHARS2 ('p', 's'): // operator + (unary) | |
| opcode = UNARY_PLUS_EXPR; | |
| break; | |
| case CHARS2 ('n', 'g'): // operator - (unary) | |
| opcode = NEGATE_EXPR; | |
| break; | |
| case CHARS2 ('a', 'd'): // operator & (unary) | |
| opcode = ADDR_EXPR; | |
| break; | |
| case CHARS2 ('d', 'e'): // operator * (unary) | |
| opcode = INDIRECT_REF; | |
| break; | |
| case CHARS2 ('c', 'o'): // operator ~ | |
| opcode = BIT_NOT_EXPR; | |
| break; | |
| case CHARS2 ('n', 't'): // operator ! | |
| opcode = TRUTH_NOT_EXPR; | |
| break; | |
| case CHARS2 ('p', 'p'): // operator ++ | |
| opcode = unary_op[2] == '_' ? PREINCREMENT_EXPR : POSTINCREMENT_EXPR; | |
| break; | |
| case CHARS2 ('m', 'm'): // operator -- | |
| opcode = unary_op[2] == '_' ? PREDECREMENT_EXPR : POSTDECREMENT_EXPR; | |
| break; | |
| case CHARS2 ('n', 'x'): // noexcept | |
| opcode = NOEXCEPT_EXPR; | |
| break; | |
| case CHARS2 ('t', 'w'): // throw | |
| gcc_assert (op0); | |
| opcode = THROW_EXPR; | |
| break; | |
| case CHARS2 ('t', 'r'): // rethrow | |
| gcc_assert (!op0); | |
| opcode = THROW_EXPR; | |
| break; | |
| case CHARS2 ('t', 'e'): // typeid (value) | |
| opcode = TYPEID_EXPR; | |
| break; | |
| case CHARS2 ('s', 'z'): // sizeof (value) | |
| opcode = SIZEOF_EXPR; | |
| break; | |
| case CHARS2 ('a', 'z'): // alignof (value) | |
| opcode = ALIGNOF_EXPR; | |
| break; | |
| case CHARS2 ('g', 's'): // global scope (for delete, delete[]) | |
| gcc_assert (!global_scope_p); | |
| global_scope_p = true; | |
| unary_op += 2; | |
| goto once_more; | |
| case CHARS2 ('d', 'l'): // delete | |
| opcode = DELETE_EXPR; | |
| break; | |
| case CHARS2 ('d', 'a'): // delete[] | |
| opcode = VEC_DELETE_EXPR; | |
| break; | |
| case CHARS2 ('s', 'p'): // pack... | |
| opcode = EXPR_PACK_EXPANSION; | |
| break; | |
| case CHARS2 ('s', 'Z'): // sizeof...(pack) | |
| opcode = TYPE_PACK_EXPANSION; // Not really, but let's use its code. | |
| break; | |
| /* FIXME: __real__, __imag__? */ | |
| default: | |
| gcc_unreachable (); | |
| } | |
| gcc_assert (!global_scope_p | |
| || opcode == DELETE_EXPR || opcode == VEC_DELETE_EXPR); | |
| processing_template_decl++; | |
| bool template_dependent_p = op0 | |
| && (type_dependent_expression_p (op0) | |
| || value_dependent_expression_p (op0)); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree result; | |
| gcc_assert (op0 || opcode == THROW_EXPR); | |
| switch (opcode) | |
| { | |
| case NOEXCEPT_EXPR: | |
| result = finish_noexcept_expr (op0, tf_error); | |
| break; | |
| case THROW_EXPR: | |
| result = build_throw (input_location, op0, tf_error); | |
| break; | |
| case TYPEID_EXPR: | |
| result = build_typeid (op0, tf_error); | |
| break; | |
| case SIZEOF_EXPR: | |
| case ALIGNOF_EXPR: | |
| result = cxx_sizeof_or_alignof_expr (input_location, | |
| op0, opcode, true, true); | |
| break; | |
| case DELETE_EXPR: | |
| case VEC_DELETE_EXPR: | |
| result = delete_sanity (input_location, op0, NULL_TREE, | |
| opcode == VEC_DELETE_EXPR, | |
| global_scope_p, tf_error); | |
| break; | |
| case EXPR_PACK_EXPANSION: | |
| result = make_pack_expansion (op0); | |
| break; | |
| /* We're using this for sizeof...(pack). */ | |
| case TYPE_PACK_EXPANSION: | |
| result = make_pack_expansion (op0); | |
| PACK_EXPANSION_SIZEOF_P (result) = true; | |
| break; | |
| default: | |
| result = build_x_unary_op (/*loc=*/0, opcode, op0, NULL_TREE, tf_error); | |
| break; | |
| } | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_expr | |
| plugin_build_binary_expr (cc1_plugin::connection *self, | |
| const char *binary_op, | |
| gcc_expr operand1, | |
| gcc_expr operand2) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree op0 = convert_in (operand1); | |
| tree op1 = convert_in (operand2); | |
| tree_code opcode = ERROR_MARK; | |
| switch (CHARS2 (binary_op[0], binary_op[1])) | |
| { | |
| case CHARS2 ('p', 'l'): // operator + | |
| opcode = PLUS_EXPR; | |
| break; | |
| case CHARS2 ('m', 'i'): // operator - | |
| opcode = MINUS_EXPR; | |
| break; | |
| case CHARS2 ('m', 'l'): // operator * | |
| opcode = MULT_EXPR; | |
| break; | |
| case CHARS2 ('d', 'v'): // operator / | |
| opcode = TRUNC_DIV_EXPR; | |
| break; | |
| case CHARS2 ('r', 'm'): // operator % | |
| opcode = TRUNC_MOD_EXPR; | |
| break; | |
| case CHARS2 ('a', 'n'): // operator & | |
| opcode = BIT_AND_EXPR; | |
| break; | |
| case CHARS2 ('o', 'r'): // operator | | |
| opcode = BIT_IOR_EXPR; | |
| break; | |
| case CHARS2 ('e', 'o'): // operator ^ | |
| opcode = BIT_XOR_EXPR; | |
| break; | |
| case CHARS2 ('l', 's'): // operator << | |
| opcode = LSHIFT_EXPR; | |
| break; | |
| case CHARS2 ('r', 's'): // operator >> | |
| opcode = RSHIFT_EXPR; | |
| break; | |
| case CHARS2 ('e', 'q'): // operator == | |
| opcode = EQ_EXPR; | |
| break; | |
| case CHARS2 ('n', 'e'): // operator != | |
| opcode = NE_EXPR; | |
| break; | |
| case CHARS2 ('l', 't'): // operator < | |
| opcode = LT_EXPR; | |
| break; | |
| case CHARS2 ('g', 't'): // operator > | |
| opcode = GT_EXPR; | |
| break; | |
| case CHARS2 ('l', 'e'): // operator <= | |
| opcode = LE_EXPR; | |
| break; | |
| case CHARS2 ('g', 'e'): // operator >= | |
| opcode = GE_EXPR; | |
| break; | |
| case CHARS2 ('a', 'a'): // operator && | |
| opcode = TRUTH_ANDIF_EXPR; | |
| break; | |
| case CHARS2 ('o', 'o'): // operator || | |
| opcode = TRUTH_ORIF_EXPR; | |
| break; | |
| case CHARS2 ('c', 'm'): // operator , | |
| opcode = COMPOUND_EXPR; | |
| break; | |
| case CHARS2 ('p', 'm'): // operator ->* | |
| opcode = MEMBER_REF; | |
| break; | |
| case CHARS2 ('p', 't'): // operator -> | |
| opcode = INDIRECT_REF; // Not really! This will stand for | |
| // INDIRECT_REF followed by COMPONENT_REF | |
| // later on. | |
| break; | |
| case CHARS2 ('i', 'x'): // operator [] | |
| opcode = ARRAY_REF; | |
| break; | |
| case CHARS2 ('d', 's'): // operator .* | |
| opcode = DOTSTAR_EXPR; | |
| break; | |
| case CHARS2 ('d', 't'): // operator . | |
| opcode = COMPONENT_REF; | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| processing_template_decl++; | |
| bool template_dependent_p = type_dependent_expression_p (op0) | |
| || value_dependent_expression_p (op0) | |
| || type_dependent_expression_p (op1) | |
| || value_dependent_expression_p (op1); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree result; | |
| switch (opcode) | |
| { | |
| case INDIRECT_REF: // This is actually a "->". | |
| op0 = build_x_arrow (/*loc=*/0, op0, tf_error); | |
| /* Fall through. */ | |
| case COMPONENT_REF: | |
| result = finish_class_member_access_expr (op0, op1, | |
| /*template_p=*/false, | |
| tf_error); | |
| break; | |
| default: | |
| result = build_x_binary_op (/*loc=*/0, opcode, op0, ERROR_MARK, | |
| op1, ERROR_MARK, NULL_TREE, NULL, tf_error); | |
| break; | |
| } | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_expr | |
| plugin_build_ternary_expr (cc1_plugin::connection *self, | |
| const char *ternary_op, | |
| gcc_expr operand1, | |
| gcc_expr operand2, | |
| gcc_expr operand3) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree op0 = convert_in (operand1); | |
| tree op1 = convert_in (operand2); | |
| tree op2 = convert_in (operand3); | |
| gcc_assert (CHARS2 (ternary_op[0], ternary_op[1]) | |
| == CHARS2 ('q', 'u')); // ternary operator | |
| processing_template_decl++; | |
| bool template_dependent_p = type_dependent_expression_p (op0) | |
| || value_dependent_expression_p (op0) | |
| || type_dependent_expression_p (op1) | |
| || value_dependent_expression_p (op1) | |
| || type_dependent_expression_p (op2) | |
| || value_dependent_expression_p (op2); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree val = build_x_conditional_expr (/*loc=*/0, op0, op1, op2, tf_error); | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| return convert_out (ctx->preserve (val)); | |
| } | |
| gcc_expr | |
| plugin_build_unary_type_expr (cc1_plugin::connection *self, | |
| const char *unary_op, | |
| gcc_type operand) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree type = convert_in (operand); | |
| tree_code opcode = ERROR_MARK; | |
| switch (CHARS2 (unary_op[0], unary_op[1])) | |
| { | |
| case CHARS2 ('t', 'i'): // typeid (type) | |
| opcode = TYPEID_EXPR; | |
| break; | |
| case CHARS2 ('s', 't'): // sizeof (type) | |
| opcode = SIZEOF_EXPR; | |
| break; | |
| case CHARS2 ('a', 't'): // alignof (type) | |
| opcode = ALIGNOF_EXPR; | |
| break; | |
| case CHARS2 ('s', 'Z'): // sizeof...(pack) | |
| opcode = TYPE_PACK_EXPANSION; // Not really, but let's use its code. | |
| break; | |
| // FIXME: do we have to handle "sp", for the size of a captured | |
| // template parameter pack from an alias template, taking | |
| // multiple template arguments? | |
| default: | |
| gcc_unreachable (); | |
| } | |
| processing_template_decl++; | |
| bool template_dependent_p = dependent_type_p (type); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree result; | |
| switch (opcode) | |
| { | |
| case TYPEID_EXPR: | |
| result = get_typeid (type, tf_error); | |
| break; | |
| // We're using this for sizeof...(pack). */ | |
| case TYPE_PACK_EXPANSION: | |
| result = make_pack_expansion (type); | |
| PACK_EXPANSION_SIZEOF_P (result) = true; | |
| break; | |
| default: | |
| /* Use the C++11 alignof semantics. */ | |
| result = cxx_sizeof_or_alignof_type (input_location, type, | |
| opcode, true, true); | |
| } | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_expr | |
| plugin_build_cast_expr (cc1_plugin::connection *self, | |
| const char *binary_op, | |
| gcc_type operand1, | |
| gcc_expr operand2) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree (*build_cast)(location_t loc, tree type, tree expr, | |
| tsubst_flags_t complain) = NULL; | |
| tree type = convert_in (operand1); | |
| tree expr = convert_in (operand2); | |
| switch (CHARS2 (binary_op[0], binary_op[1])) | |
| { | |
| case CHARS2 ('d', 'c'): // dynamic_cast | |
| build_cast = build_dynamic_cast; | |
| break; | |
| case CHARS2 ('s', 'c'): // static_cast | |
| build_cast = build_static_cast; | |
| break; | |
| case CHARS2 ('c', 'c'): // const_cast | |
| build_cast = build_const_cast; | |
| break; | |
| case CHARS2 ('r', 'c'): // reinterpret_cast | |
| build_cast = build_reinterpret_cast; | |
| break; | |
| case CHARS2 ('c', 'v'): // C cast, conversion with one argument | |
| build_cast = cp_build_c_cast; | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| processing_template_decl++; | |
| bool template_dependent_p = dependent_type_p (type) | |
| || type_dependent_expression_p (expr) | |
| || value_dependent_expression_p (expr); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree val = build_cast (input_location, type, expr, tf_error); | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| return convert_out (ctx->preserve (val)); | |
| } | |
| static inline vec<tree, va_gc> * | |
| args_to_tree_vec (const struct gcc_cp_function_args *args_in) | |
| { | |
| vec<tree, va_gc> *args = make_tree_vector (); | |
| for (int i = 0; i < args_in->n_elements; i++) | |
| vec_safe_push (args, convert_in (args_in->elements[i])); | |
| return args; | |
| } | |
| static inline tree | |
| args_to_tree_list (const struct gcc_cp_function_args *args_in) | |
| { | |
| tree args, *tail = &args; | |
| for (int i = 0; i < args_in->n_elements; i++) | |
| { | |
| *tail = build_tree_list (NULL, convert_in (args_in->elements[i])); | |
| tail = &TREE_CHAIN (*tail); | |
| } | |
| return args; | |
| } | |
| static inline vec<constructor_elt, va_gc> * | |
| args_to_ctor_elts (const struct gcc_cp_function_args *args_in) | |
| { | |
| vec<constructor_elt, va_gc> *args = NULL; | |
| for (int i = 0; i < args_in->n_elements; i++) | |
| CONSTRUCTOR_APPEND_ELT (args, NULL_TREE, convert_in (args_in->elements[i])); | |
| return args; | |
| } | |
| gcc_expr | |
| plugin_build_expression_list_expr (cc1_plugin::connection *self, | |
| const char *conv_op, | |
| gcc_type type_in, | |
| const struct gcc_cp_function_args *values_in) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree type = convert_in (type_in); | |
| tree args; | |
| tree result; | |
| switch (CHARS2 (conv_op[0], conv_op[1])) | |
| { | |
| case CHARS2 ('c', 'v'): // conversion with parenthesized expression list | |
| gcc_assert (TYPE_P (type)); | |
| args = args_to_tree_list (values_in); | |
| result = build_functional_cast (input_location, type, args, tf_error); | |
| break; | |
| case CHARS2 ('t', 'l'): // conversion with braced expression list | |
| gcc_assert (type); | |
| gcc_assert (TYPE_P (type)); | |
| args = make_node (CONSTRUCTOR); | |
| CONSTRUCTOR_ELTS (args) = args_to_ctor_elts (values_in); | |
| CONSTRUCTOR_IS_DIRECT_INIT (args) = 1; | |
| result = finish_compound_literal (type, args, tf_error); | |
| break; | |
| case CHARS2 ('i', 'l'): // untyped braced expression list | |
| gcc_assert (!type); | |
| result = make_node (CONSTRUCTOR); | |
| CONSTRUCTOR_ELTS (result) = args_to_ctor_elts (values_in); | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_expr | |
| plugin_build_new_expr (cc1_plugin::connection *self, | |
| const char *new_op, | |
| const struct gcc_cp_function_args *placement_in, | |
| gcc_type type_in, | |
| const struct gcc_cp_function_args *initializer_in) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree type = convert_in (type_in); | |
| vec<tree, va_gc> *placement = NULL, *initializer = NULL; | |
| bool global_scope_p = false; | |
| tree nelts = NULL; | |
| if (placement_in) | |
| placement = args_to_tree_vec (placement_in); | |
| if (initializer_in) | |
| initializer = args_to_tree_vec (initializer_in); | |
| gcc_assert (TYPE_P (type)); | |
| once_more: | |
| switch (CHARS2 (new_op[0], new_op[1])) | |
| { | |
| case CHARS2 ('g', 's'): | |
| gcc_assert (!global_scope_p); | |
| global_scope_p = true; | |
| new_op += 2; | |
| goto once_more; | |
| case CHARS2 ('n', 'w'): // non-array new | |
| gcc_assert (TREE_CODE (type) != ARRAY_TYPE); | |
| break; | |
| case CHARS2 ('n', 'a'): // array new | |
| gcc_assert (TREE_CODE (type) == ARRAY_TYPE); | |
| gcc_assert (TYPE_DOMAIN (type)); | |
| { | |
| // Compute the length of the outermost array type, then discard it. | |
| tree maxelt = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); | |
| tree eltype = TREE_TYPE (maxelt); | |
| tree onecst = integer_one_node; | |
| processing_template_decl++; | |
| bool template_dependent_p = value_dependent_expression_p (maxelt) | |
| || type_dependent_expression_p (maxelt); | |
| if (!template_dependent_p) | |
| { | |
| processing_template_decl--; | |
| onecst = fold_convert (eltype, onecst); | |
| } | |
| nelts = fold_build2 (PLUS_EXPR, eltype, nelts, onecst); | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| type = TREE_TYPE (type); | |
| } | |
| break; | |
| default: | |
| gcc_unreachable (); | |
| } | |
| processing_template_decl++; | |
| bool template_dependent_p = dependent_type_p (type) | |
| || value_dependent_expression_p (nelts) | |
| || (placement | |
| && any_type_dependent_arguments_p (placement)) | |
| || (initializer | |
| && any_type_dependent_arguments_p (initializer)); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree result = build_new (input_location, &placement, type, nelts, | |
| &initializer, global_scope_p, tf_error); | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| if (placement != NULL) | |
| release_tree_vector (placement); | |
| if (initializer != NULL) | |
| release_tree_vector (initializer); | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_expr | |
| plugin_build_call_expr (cc1_plugin::connection *self, | |
| gcc_expr callable_in, int qualified_p, | |
| const struct gcc_cp_function_args *args_in) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree callable = convert_in (callable_in); | |
| tree call_expr; | |
| vec<tree, va_gc> *args = args_to_tree_vec (args_in); | |
| bool koenig_p = false; | |
| if (!qualified_p && !args->is_empty ()) | |
| { | |
| if (identifier_p (callable)) | |
| koenig_p = true; | |
| else if (is_overloaded_fn (callable)) | |
| { | |
| tree fn = get_first_fn (callable); | |
| fn = STRIP_TEMPLATE (fn); | |
| if (!DECL_FUNCTION_MEMBER_P (fn) | |
| && !DECL_LOCAL_DECL_P (fn)) | |
| koenig_p = true; | |
| } | |
| } | |
| if (koenig_p && !any_type_dependent_arguments_p (args)) | |
| callable = perform_koenig_lookup (callable, args, tf_none); | |
| if (TREE_CODE (callable) == COMPONENT_REF) | |
| { | |
| tree object = TREE_OPERAND (callable, 0); | |
| tree memfn = TREE_OPERAND (callable, 1); | |
| if (type_dependent_expression_p (object) | |
| || (!BASELINK_P (memfn) && TREE_CODE (memfn) != FIELD_DECL) | |
| || type_dependent_expression_p (memfn) | |
| || any_type_dependent_arguments_p (args)) | |
| call_expr = build_nt_call_vec (callable, args); | |
| else if (BASELINK_P (memfn)) | |
| call_expr = build_new_method_call (object, memfn, &args, NULL_TREE, | |
| qualified_p | |
| ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL | |
| : LOOKUP_NORMAL, | |
| NULL, tf_none); | |
| else | |
| call_expr = finish_call_expr (callable, &args, false, false, tf_none); | |
| } | |
| else if (TREE_CODE (callable) == OFFSET_REF | |
| || TREE_CODE (callable) == MEMBER_REF | |
| || TREE_CODE (callable) == DOTSTAR_EXPR) | |
| call_expr = build_offset_ref_call_from_tree (callable, &args, tf_none); | |
| else | |
| call_expr = finish_call_expr (callable, &args, | |
| !!qualified_p, koenig_p, tf_none); | |
| release_tree_vector (args); | |
| return convert_out (ctx->preserve (call_expr)); | |
| } | |
| gcc_type | |
| plugin_get_expr_type (cc1_plugin::connection *self, | |
| gcc_expr operand) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree op0 = convert_in (operand); | |
| tree type; | |
| if (op0) | |
| type = TREE_TYPE (op0); | |
| else | |
| type = make_decltype_auto (); | |
| return convert_out (ctx->preserve (type)); | |
| } | |
| gcc_decl | |
| plugin_build_function_template_specialization (cc1_plugin::connection *self, | |
| gcc_decl template_decl, | |
| const gcc_cp_template_args *targs, | |
| gcc_address address, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| tree name = convert_in (template_decl); | |
| tree targsl = targlist (targs); | |
| tree decl = tsubst (name, targsl, tf_error, NULL_TREE); | |
| DECL_SOURCE_LOCATION (decl) = loc; | |
| record_decl_address (ctx, build_decl_addr_value (decl, address)); | |
| return convert_out (ctx->preserve (decl)); | |
| } | |
| gcc_decl | |
| plugin_build_class_template_specialization (cc1_plugin::connection *self, | |
| gcc_decl template_decl, | |
| const gcc_cp_template_args *args, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| tree name = convert_in (template_decl); | |
| tree tdecl = finish_template_type (name, targlist (args), false);; | |
| DECL_SOURCE_LOCATION (tdecl) = loc; | |
| return convert_out (ctx->preserve (tdecl)); | |
| } | |
| /* Return a builtin type associated with BUILTIN_NAME. */ | |
| static tree | |
| safe_lookup_builtin_type (const char *builtin_name) | |
| { | |
| tree result = NULL_TREE; | |
| if (!builtin_name) | |
| return result; | |
| result = identifier_global_value (get_identifier (builtin_name)); | |
| if (!result) | |
| return result; | |
| gcc_assert (TREE_CODE (result) == TYPE_DECL); | |
| result = TREE_TYPE (result); | |
| return result; | |
| } | |
| gcc_type | |
| plugin_get_int_type (cc1_plugin::connection *self, | |
| int is_unsigned, unsigned long size_in_bytes, | |
| const char *builtin_name) | |
| { | |
| tree result; | |
| if (builtin_name) | |
| { | |
| result = safe_lookup_builtin_type (builtin_name); | |
| gcc_assert (!result || TREE_CODE (result) == INTEGER_TYPE); | |
| } | |
| else | |
| result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes, | |
| is_unsigned); | |
| if (result == NULL_TREE) | |
| result = error_mark_node; | |
| else | |
| { | |
| gcc_assert (!TYPE_UNSIGNED (result) == !is_unsigned); | |
| gcc_assert (TREE_CODE (TYPE_SIZE (result)) == INTEGER_CST); | |
| gcc_assert (TYPE_PRECISION (result) == BITS_PER_UNIT * size_in_bytes); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| ctx->preserve (result); | |
| } | |
| return convert_out (result); | |
| } | |
| gcc_type | |
| plugin_get_char_type (cc1_plugin::connection *) | |
| { | |
| return convert_out (char_type_node); | |
| } | |
| gcc_type | |
| plugin_get_float_type (cc1_plugin::connection *, | |
| unsigned long size_in_bytes, | |
| const char *builtin_name) | |
| { | |
| if (builtin_name) | |
| { | |
| tree result = safe_lookup_builtin_type (builtin_name); | |
| if (!result) | |
| return convert_out (error_mark_node); | |
| gcc_assert (SCALAR_FLOAT_TYPE_P (result)); | |
| gcc_assert (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (result)); | |
| return convert_out (result); | |
| } | |
| if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node)) | |
| return convert_out (float_type_node); | |
| if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node)) | |
| return convert_out (double_type_node); | |
| if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node)) | |
| return convert_out (long_double_type_node); | |
| return convert_out (error_mark_node); | |
| } | |
| gcc_type | |
| plugin_get_void_type (cc1_plugin::connection *) | |
| { | |
| return convert_out (void_type_node); | |
| } | |
| gcc_type | |
| plugin_get_bool_type (cc1_plugin::connection *) | |
| { | |
| return convert_out (boolean_type_node); | |
| } | |
| gcc_type | |
| plugin_get_nullptr_type (cc1_plugin::connection *) | |
| { | |
| return convert_out (nullptr_type_node); | |
| } | |
| gcc_expr | |
| plugin_get_nullptr_constant (cc1_plugin::connection *) | |
| { | |
| return convert_out (nullptr_node); | |
| } | |
| gcc_type | |
| plugin_build_array_type (cc1_plugin::connection *self, | |
| gcc_type element_type_in, int num_elements) | |
| { | |
| tree element_type = convert_in (element_type_in); | |
| tree result; | |
| if (num_elements == -1) | |
| result = build_array_type (element_type, NULL_TREE); | |
| else | |
| result = build_array_type_nelts (element_type, num_elements); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_type | |
| plugin_build_dependent_array_type (cc1_plugin::connection *self, | |
| gcc_type element_type_in, | |
| gcc_expr num_elements_in) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree element_type = convert_in (element_type_in); | |
| tree size = convert_in (num_elements_in); | |
| tree name = get_identifier ("dependent array type"); | |
| processing_template_decl++; | |
| bool template_dependent_p = dependent_type_p (element_type) | |
| || type_dependent_expression_p (size) | |
| || value_dependent_expression_p (size); | |
| if (!template_dependent_p) | |
| processing_template_decl--; | |
| tree itype = compute_array_index_type (name, size, tf_error); | |
| tree type = build_cplus_array_type (element_type, itype); | |
| if (template_dependent_p) | |
| processing_template_decl--; | |
| return convert_out (ctx->preserve (type)); | |
| } | |
| gcc_type | |
| plugin_build_vla_array_type (cc1_plugin::connection *self, | |
| gcc_type element_type_in, | |
| const char *upper_bound_name) | |
| { | |
| tree element_type = convert_in (element_type_in); | |
| tree upper_bound = lookup_name (get_identifier (upper_bound_name)); | |
| tree size = fold_build2 (PLUS_EXPR, TREE_TYPE (upper_bound), upper_bound, | |
| build_one_cst (TREE_TYPE (upper_bound))); | |
| tree range = compute_array_index_type (NULL_TREE, size, | |
| tf_error); | |
| tree result = build_cplus_array_type (element_type, range); | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (result)); | |
| } | |
| gcc_type | |
| plugin_build_qualified_type (cc1_plugin::connection *, | |
| gcc_type unqualified_type_in, | |
| enum gcc_cp_qualifiers qualifiers) | |
| { | |
| tree unqualified_type = convert_in (unqualified_type_in); | |
| cp_cv_quals quals = 0; | |
| if ((qualifiers & GCC_CP_QUALIFIER_CONST) != 0) | |
| quals |= TYPE_QUAL_CONST; | |
| if ((qualifiers & GCC_CP_QUALIFIER_VOLATILE) != 0) | |
| quals |= TYPE_QUAL_VOLATILE; | |
| if ((qualifiers & GCC_CP_QUALIFIER_RESTRICT) != 0) | |
| quals |= TYPE_QUAL_RESTRICT; | |
| gcc_assert ((TREE_CODE (unqualified_type) != METHOD_TYPE | |
| && TREE_CODE (unqualified_type) != REFERENCE_TYPE) | |
| || quals == 0); | |
| return convert_out (build_qualified_type (unqualified_type, quals)); | |
| } | |
| gcc_type | |
| plugin_build_complex_type (cc1_plugin::connection *self, | |
| gcc_type base_type) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (build_complex_type (convert_in (base_type)))); | |
| } | |
| gcc_type | |
| plugin_build_vector_type (cc1_plugin::connection *self, | |
| gcc_type base_type, int nunits) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| return convert_out (ctx->preserve (build_vector_type (convert_in (base_type), | |
| nunits))); | |
| } | |
| int | |
| plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in, | |
| const char *name, unsigned long value, | |
| const char *filename, unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree cst, decl; | |
| tree type = convert_in (type_in); | |
| cst = build_int_cst (type, value); | |
| if (!TYPE_READONLY (type)) | |
| type = build_qualified_type (type, TYPE_QUAL_CONST); | |
| decl = build_decl (ctx->get_location_t (filename, line_number), | |
| VAR_DECL, get_identifier (name), type); | |
| TREE_STATIC (decl) = 1; | |
| TREE_READONLY (decl) = 1; | |
| cp_finish_decl (decl, cst, true, NULL, LOOKUP_ONLYCONVERTING); | |
| safe_pushdecl (decl); | |
| return 1; | |
| } | |
| gcc_type | |
| plugin_error (cc1_plugin::connection *, | |
| const char *message) | |
| { | |
| error ("%s", message); | |
| return convert_out (error_mark_node); | |
| } | |
| int | |
| plugin_add_static_assert (cc1_plugin::connection *self, | |
| gcc_expr condition_in, | |
| const char *errormsg, | |
| const char *filename, | |
| unsigned int line_number) | |
| { | |
| plugin_context *ctx = static_cast<plugin_context *> (self); | |
| tree condition = convert_in (condition_in); | |
| if (!errormsg) | |
| errormsg = ""; | |
| tree message = build_string (strlen (errormsg) + 1, errormsg); | |
| TREE_TYPE (message) = char_array_type_node; | |
| fix_string_type (message); | |
| location_t loc = ctx->get_location_t (filename, line_number); | |
| bool member_p = at_class_scope_p (); | |
| finish_static_assert (condition, message, loc, member_p, false); | |
| return 1; | |
| } | |
| #ifdef __GNUC__ | |
| #pragma GCC visibility push(default) | |
| #endif | |
| int | |
| plugin_init (struct plugin_name_args *plugin_info, | |
| struct plugin_gcc_version *) | |
| { | |
| generic_plugin_init (plugin_info, GCC_CP_FE_VERSION_0); | |
| register_callback (plugin_info->base_name, PLUGIN_PRAGMAS, | |
| plugin_init_extra_pragmas, NULL); | |
| register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE, | |
| rewrite_decls_to_addresses, NULL); | |
| #define GCC_METHOD0(R, N) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #define GCC_METHOD1(R, N, A) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R, A>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #define GCC_METHOD2(R, N, A, B) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R, A, B>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #define GCC_METHOD3(R, N, A, B, C) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R, A, B, C>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #define GCC_METHOD4(R, N, A, B, C, D) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R, A, B, C, \ | |
| D>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #define GCC_METHOD5(R, N, A, B, C, D, E) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R, A, B, C, \ | |
| D, E>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \ | |
| { \ | |
| cc1_plugin::callback_ftype *fun \ | |
| = cc1_plugin::invoker<R, A, B, C, \ | |
| D, E, F, G>::invoke<plugin_ ## N>; \ | |
| current_context->add_callback (# N, fun); \ | |
| } | |
| #include "gcc-cp-fe.def" | |
| #undef GCC_METHOD0 | |
| #undef GCC_METHOD1 | |
| #undef GCC_METHOD2 | |
| #undef GCC_METHOD3 | |
| #undef GCC_METHOD4 | |
| #undef GCC_METHOD5 | |
| #undef GCC_METHOD7 | |
| return 0; | |
| } |