Hi This patch adds a plugin event when evaluating a call expression in constexpr. The goal of this patch is to allow the plugins to analyze and or modify the evaluation of constant expressions.
Changelog 2016-4-25 Andres Tiraboschi <andres.tirabos...@tallertechnologies.com> *gcc/plugin.c (PLUGIN_EVAL_CALL_CONSTEXPR): New event. *gcc/plugin.def (PLUGIN_EVAL_CALL_CONSTEXPR): New event. *gcc/cp/constexpr.c (constexpr_fundef): Moved to gcc/cp/cp-tree.h. *gcc/cp/constexpr.c (constexpr_call): Ditto. *gcc/cp/constexpr.c (constexpr_ctx): Ditto. *gcc/cp/constexpr.c (cxx_eval_constant_expression): Not static anymore. *gcc/pc/cp-tree.h (constexpr_call_info): New Type. *gcc/pc/cp-tree.h (constexpr_fundef): Moved type from gcc/cp/constexpr.c. *gcc/pc/cp-tree.h (constexpr_call): Ditto. *gcc/pc/cp-tree.h (constexpr_ctx): Ditto. *gcc/pc/cp-tree.h (cxx_eval_constant_expression): Declared. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 5f97c9d..5562e44 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -31,6 +31,8 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "tree-inline.h" #include "ubsan.h" +#include "plugin-api.h" +#include "plugin.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -112,13 +114,6 @@ ensure_literal_type_for_constexpr_object (tree decl) return decl; } -/* Representation of entries in the constexpr function definition table. */ - -struct GTY((for_user)) constexpr_fundef { - tree decl; - tree body; -}; - struct constexpr_fundef_hasher : ggc_ptr_hash<constexpr_fundef> { static hashval_t hash (constexpr_fundef *); @@ -856,62 +851,12 @@ explain_invalid_constexpr_fn (tree fun) input_location = save_loc; } -/* Objects of this type represent calls to constexpr functions - along with the bindings of parameters to their arguments, for - the purpose of compile time evaluation. */ - -struct GTY((for_user)) constexpr_call { - /* Description of the constexpr function definition. */ - constexpr_fundef *fundef; - /* Parameter bindings environment. A TREE_LIST where each TREE_PURPOSE - is a parameter _DECL and the TREE_VALUE is the value of the parameter. - Note: This arrangement is made to accommodate the use of - iterative_hash_template_arg (see pt.c). If you change this - representation, also change the hash calculation in - cxx_eval_call_expression. */ - tree bindings; - /* Result of the call. - NULL means the call is being evaluated. - error_mark_node means that the evaluation was erroneous; - otherwise, the actuall value of the call. */ - tree result; - /* The hash of this call; we remember it here to avoid having to - recalculate it when expanding the hash table. */ - hashval_t hash; -}; - struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call> { static hashval_t hash (constexpr_call *); static bool equal (constexpr_call *, constexpr_call *); }; -/* The constexpr expansion context. CALL is the current function - expansion, CTOR is the current aggregate initializer, OBJECT is the - object being initialized by CTOR, either a VAR_DECL or a _REF. VALUES - is a map of values of variables initialized within the expression. */ - -struct constexpr_ctx { - /* The innermost call we're evaluating. */ - constexpr_call *call; - /* Values for any temporaries or local variables within the - constant-expression. */ - hash_map<tree,tree> *values; - /* SAVE_EXPRs that we've seen within the current LOOP_EXPR. NULL if we - aren't inside a loop. */ - hash_set<tree> *save_exprs; - /* The CONSTRUCTOR we're currently building up for an aggregate - initializer. */ - tree ctor; - /* The object we're building the CONSTRUCTOR for. */ - tree object; - /* Whether we should error on a non-constant expression or fail quietly. */ - bool quiet; - /* Whether we are strictly conforming to constant expression rules or - trying harder to get a constant value. */ - bool strict; -}; - /* A table of all constexpr calls that have been evaluated by the compiler in this translation unit. */ @@ -1303,6 +1248,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, bool non_constant_args = false; cxx_bind_parameters_in_call (ctx, t, &new_call, non_constant_p, overflow_p, &non_constant_args); + + constexpr_call_info call_info; + call_info.function = t; + call_info.lval = lval; + call_info.call = &new_call; + call_info.call_stack = call_stack; + call_info.non_constant_args = &non_constant_args; + call_info.non_const_p = non_constant_p; + call_info.ctx = ctx; + call_info.result = NULL_TREE; + invoke_plugin_callbacks (PLUGIN_EVAL_CALL_CONSTEXPR, &call_info); + if (call_info.result != NULL_TREE) + { + return call_info.result; + } + if (*non_constant_p) return t; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 15b004d..00856ec 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6946,6 +6946,77 @@ extern tree cp_ubsan_maybe_instrument_downcast (location_t, tree, tree, tree); extern tree cp_ubsan_maybe_instrument_cast_to_vbase (location_t, tree, tree); extern void cp_ubsan_maybe_initialize_vtbl_ptrs (tree); +/* Representation of entries in the constexpr function definition table. */ + +struct GTY((for_user)) constexpr_fundef { + tree decl; + tree body; +}; + +/* Objects of this type represent calls to constexpr functions + along with the bindings of parameters to their arguments, for + the purpose of compile time evaluation. */ + +struct GTY((for_user)) constexpr_call { + /* Description of the constexpr function definition. */ + constexpr_fundef *fundef; + /* Parameter bindings environment. A TREE_LIST where each TREE_PURPOSE + is a parameter _DECL and the TREE_VALUE is the value of the parameter. + Note: This arrangement is made to accommodate the use of + iterative_hash_template_arg (see pt.c). If you change this + representation, also change the hash calculation in + cxx_eval_call_expression. */ + tree bindings; + /* Result of the call. + NULL means the call is being evaluated. + error_mark_node means that the evaluation was erroneous; + otherwise, the actuall value of the call. */ + tree result; + /* The hash of this call; we remember it here to avoid having to + recalculate it when expanding the hash table. */ + hashval_t hash; +}; + +/* The constexpr expansion context. CALL is the current function + expansion, CTOR is the current aggregate initializer, OBJECT is the + object being initialized by CTOR, either a VAR_DECL or a _REF. VALUES + is a map of values of variables initialized within the expression. */ + +struct constexpr_ctx { + /* The innermost call we're evaluating. */ + constexpr_call *call; + /* Values for any temporaries or local variables within the + constant-expression. */ + hash_map<tree,tree> *values; + /* SAVE_EXPRs that we've seen within the current LOOP_EXPR. NULL if we + aren't inside a loop. */ + hash_set<tree> *save_exprs; + /* The CONSTRUCTOR we're currently building up for an aggregate + initializer. */ + tree ctor; + /* The object we're building the CONSTRUCTOR for. */ + tree object; + /* Whether we should error on a non-constant expression or fail quietly. */ + bool quiet; + /* Whether we are strictly conforming to constant expression rules or + trying harder to get a constant value. */ + bool strict; +}; + +/* This type represents a function call into a constant expression.*/ +typedef struct constexpr_call_info_st +{ + tree function; //Function named in call. + tree result; //Function call result. + vec<tree> call_stack; //Call stack. + bool lval; + bool* non_constant_args; //The function arguments are constant. + bool* non_const_p; //Is constant. + bool* overflow; + constexpr_call* call; //Call to the constexpr function. + const struct constexpr_ctx* ctx; //constexpr expansion context. +} constexpr_call_info; + /* -- end of C++ */ #endif /* ! GCC_CP_TREE_H */ diff --git a/gcc/plugin.c b/gcc/plugin.c index 60081a5..34c60ed 100644 --- a/gcc/plugin.c +++ b/gcc/plugin.c @@ -427,6 +427,7 @@ register_callback (const char *plugin_name, return; } /* Fall through. */ + case PLUGIN_EVAL_CALL_CONSTEXPR: case PLUGIN_START_PARSE_FUNCTION: case PLUGIN_FINISH_PARSE_FUNCTION: case PLUGIN_FINISH_TYPE: @@ -507,6 +508,7 @@ invoke_plugin_callbacks_full (int event, void *gcc_data) gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC); gcc_assert (event < event_last); /* Fall through. */ + case PLUGIN_EVAL_CALL_CONSTEXPR: case PLUGIN_START_PARSE_FUNCTION: case PLUGIN_FINISH_PARSE_FUNCTION: case PLUGIN_FINISH_TYPE: diff --git a/gcc/plugin.def b/gcc/plugin.def index c926d41..824f807 100644 --- a/gcc/plugin.def +++ b/gcc/plugin.def @@ -17,6 +17,9 @@ 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/>. */ +/* Called when evaluating a constexpr call. */ +DEFEVENT (PLUGIN_EVAL_CALL_CONSTEXPR) + /* Called before parsing the body of a function. */ DEFEVENT (PLUGIN_START_PARSE_FUNCTION)