diff options
author | Nathan Sidwell <nathan@gcc.gnu.org> | 2001-04-24 08:22:06 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2001-04-24 08:22:06 +0000 |
commit | 0ba8a114c724d36034e8996eefb7c94d4fe8aed0 (patch) | |
tree | 268353894884ce2459e1f3b08adc4825b8ed0dd6 /gcc/c-common.c | |
parent | dfbb4f347cf43b955f56ecbc9709b8836d395ee5 (diff) | |
download | gcc-0ba8a114c724d36034e8996eefb7c94d4fe8aed0.zip gcc-0ba8a114c724d36034e8996eefb7c94d4fe8aed0.tar.gz gcc-0ba8a114c724d36034e8996eefb7c94d4fe8aed0.tar.bz2 |
Lazy __FUNCTION__ generation.
gcc:
Lazy __FUNCTION__ generation.
* c-common.h (RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME,
RID_C99_FUNCTION_NAME): New _RIDs.
(CTI_FUNCTION_ID, CTI_PRETTY_FUNCTION_ID, CTI_FUNC_ID): Remove.
(CTI_FUNCTION_NAME_DECL, CTI_PRETTY_FUNCTION_NAME_DECL,
CTI_C99_FUNCTION_NAME_DECL, CTI_SAVED_FUNCTION_NAME_DECLS): New
global tree slots.
(function_id_node, pretty_function_id_node, func_id_node): Remove.
(c99_function_name_decl_node, function_name_decl_node,
pretty_function_name_decl_node, saved_function_name_decls):
Declare.
(struct language_function): Remove x_function_name_declared_p.
(make_fname_decl): Remove a parameter.
(declare_function_names): Remove prototype.
(start_fname_decls, finish_fname_decls): Prototype.
(fname_as_string): Likewise.
(fname_string, fname_decl): Likewise.
* c-common.c (make_fname_decl): Adjust.
(struct fname_var_t): New struct.
(fname_vars): New static array.
(declare_function_name): Remove.
(start_fname_decls, finish_fname_decls): New functions.
(fname_as_string): New function from remnants of
declare_function_name.
(fname_string, fname_decl): New functions.
* c-decl.c (c_function_name_declared_p): Remove.
(init_decl_processing): Don't generate __FUNCTION__ et al ids,
don't call declare_function_name. Call start_fname_decls.
(c_make_fname_decl): Adjust parameters. Generate the name. Don't
clobber the line number. Call finish_decl.
(start_function): Call start_fname_decls.
(finish_function): Call finish_fname_decls.
Remove c_function_name_declared_p.
(push_c_function_context): Don't push c_function_name_declared_p.
(pop_c_function_context): Don't pop c_function_name_declared_p.
(c_begin_compound_stmt): Don't check c_function_name_declared_p.
* c-parse.in (STRING_FUNC_NAME, VAR_FUNC_NAME): New tokens.
(program): Call finish_fname_decls for C.
(primary): Add VAR_FUNC_NAME.
(reswords): Add slots for __FUNCTION__ et al.
(rid_to_yy): Add mappings for __FUNCTION__ et al.
(yylexname): If it's a STRING_FUNC_NAME generate the function name
now. Don't look for VAR_DECLs containing __FUNCTION__ et al.
* c-semantics.c (prune_unused_decls): Remove.
(finish_stmt_tree): Don't call prune_unused_decls.
(genrtl_decl_stmt): Don't prune unused decls here.
cp:
Lazy __FUNCTION__ generation.
* cp-tree.def (FUNCTION_NAME): Remove.
* cp-tree.h (function_name_declared_p): Remove.
(cp_fname_init): Prototype.
* decl.c (init_decl_processing): Don't generate __FUNCTION__ et al ids,
don't call declare_function_name. Call start_fname_decls.
(cp_make_fname_decl): Adjust parameters. Generate the name. Don't
clobber the line number.
(cp_fname_init): New function.
(start_function): Call start_fname_decls.
(finish_function): Call finish_fname_decls.
* lex.c (reswords): Add slots for __FUNCTION__ et al.
(rid_to_yy): Add mappings for __FUNCTION__ et al.
* optimize.c (maybe_clone_body): Remove function_name_declared_p.
* parse.y (VAR_FUNC_NAME): New token.
(primary): Add VAR_FUNC_NAME.
* pt.c (tsubst_decl): Adjust a DECL_PRETTY_FUNCTION_P's
generation.
(tsubst, FUNCTION_NAME case): Remove.
(tsubst_copy, FUNCTION_NAME case): Remove.
(tsubst_expr, DECL_STMT case): Be careful with a
DECL_PRETTY_FUNCTION_P.
(instantiate_decl): Remove function_name_declared_p.
* semantics.c (begin_compound_statement): Don't call
declare_function_name here.
(setup_vtbl_ptr). Don't save & restore function_name_declared_p.
(finish_translation_unit): Call finish_fname_decls.
(expand_body): Remove function_name_declared_p.
* typeck2.c (digest_init): Allow any ERROR_MARK.
testsuite:
* gcc.dg/c99-func-2.c: Remove xfail.
* gcc.dg/c99-func-3.c: Remove xfail.
* gcc.dg/c99-func-4.c: Remove xfail.
From-SVN: r41520
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 196 |
1 files changed, 173 insertions, 23 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 1b00362..8727503 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -164,11 +164,17 @@ cpp_reader *parse_in; /* Declared in c-lex.h. */ tree void_list_node; - The identifiers __FUNCTION__, __PRETTY_FUNCTION__, and __func__. + The lazily created VAR_DECLS for __FUNCTION__, __PRETTY_FUNCTION__, + and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__ + VAR_DECLS, but C++ does.) - tree function_id_node; - tree pretty_function_id_node; - tree func_id_node; + tree function_name_decl_node; + tree pretty_function_name_declnode; + tree c99_function_name_decl_node; + + Stack of nested function name VAR_DECLs. + + tree saved_function_name_decls; */ @@ -204,7 +210,7 @@ int warn_sequence_point; type names and storage classes. It is indexed by a RID_... value. */ tree *ridpointers; -tree (*make_fname_decl) PARAMS ((tree, const char *, int)); +tree (*make_fname_decl) PARAMS ((tree, int)); /* If non-NULL, the address of a language-specific function that returns 1 for language-specific statement codes. */ @@ -228,6 +234,27 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION, A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC, A_NO_LIMIT_STACK, A_PURE}; +/* Information about how a function name is generated. */ +struct fname_var_t +{ + tree *decl; /* pointer to the VAR_DECL. */ + unsigned rid; /* RID number for the identifier. */ + int pretty; /* How pretty is it? */ +}; + +/* The three ways of getting then name of the current function. */ + +const struct fname_var_t fname_vars[] = +{ + /* C99 compliant __func__, must be first. */ + {&c99_function_name_decl_node, RID_C99_FUNCTION_NAME, 0}, + /* GCC __FUNCTION__ compliant. */ + {&function_name_decl_node, RID_FUNCTION_NAME, 0}, + /* GCC __PRETTY_FUNCTION__ compliant. */ + {&pretty_function_name_decl_node, RID_PRETTY_FUNCTION_NAME, 1}, + {NULL, 0, 0}, +}; + static void add_attribute PARAMS ((enum attrs, const char *, int, int, int)); static void init_attributes PARAMS ((void)); @@ -344,34 +371,157 @@ c_finish_else () RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt)); } -/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__. */ +/* Push current bindings for the function name VAR_DECLS. */ + +void +start_fname_decls () +{ + unsigned ix; + tree saved = NULL_TREE; + + for (ix = 0; fname_vars[ix].decl; ix++) + { + tree decl = *fname_vars[ix].decl; + + if (decl) + { + saved = tree_cons (decl, build_int_2 (ix, 0), saved); + *fname_vars[ix].decl = NULL_TREE; + } + } + if (saved || saved_function_name_decls) + /* Normally they'll have been NULL, so only push if we've got a + stack, or they are non-NULL. */ + saved_function_name_decls = tree_cons (saved, NULL_TREE, + saved_function_name_decls); +} + +/* Finish up the current bindings, adding them into the + current function's statement tree. This is done by wrapping the + function's body in a COMPOUND_STMT containing these decls too. This + must be done _before_ finish_stmt_tree is called. If there is no + current function, we must be at file scope and no statements are + involved. Pop the previous bindings. */ void -declare_function_name () +finish_fname_decls () { - const char *name, *printable_name; + unsigned ix; + tree body = NULL_TREE; + tree stack = saved_function_name_decls; - if (current_function_decl == NULL) + for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack)) + body = chainon (TREE_VALUE (stack), body); + + if (body) { - name = ""; - printable_name = "top level"; + /* They were called into existance, so add to statement tree. */ + body = chainon (body, + TREE_CHAIN (DECL_SAVED_TREE (current_function_decl))); + body = build_stmt (COMPOUND_STMT, body); + + COMPOUND_STMT_NO_SCOPE (body) = 1; + TREE_CHAIN (DECL_SAVED_TREE (current_function_decl)) = body; } - else + + for (ix = 0; fname_vars[ix].decl; ix++) + *fname_vars[ix].decl = NULL_TREE; + + if (stack) { - /* Allow functions to be nameless (such as artificial ones). */ - if (DECL_NAME (current_function_decl)) - name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); - else - name = ""; - printable_name = (*decl_printable_name) (current_function_decl, 2); + /* We had saved values, restore them. */ + tree saved; - /* ISO C99 defines __func__, which is a variable, not a string - constant, and which is not a defined symbol at file scope. */ - (*make_fname_decl) (func_id_node, name, 0); + for (saved = TREE_PURPOSE (stack); saved; saved = TREE_CHAIN (saved)) + { + tree decl = TREE_PURPOSE (saved); + unsigned ix = TREE_INT_CST_LOW (TREE_VALUE (saved)); + + *fname_vars[ix].decl = decl; + } + stack = TREE_CHAIN (stack); + } + saved_function_name_decls = stack; +} + +/* Return the text name of the current function, suitable prettified + by PRETTY_P. */ + +const char * +fname_as_string (pretty_p) + int pretty_p; +{ + const char *name = NULL; + + if (pretty_p) + name = (current_function_decl + ? (*decl_printable_name) (current_function_decl, 2) + : "top level"); + else if (current_function_decl && DECL_NAME (current_function_decl)) + name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); + else + name = ""; + return name; +} + +/* Return the text name of the current function, formatted as + required by the supplied RID value. */ + +const char * +fname_string (rid) + unsigned rid; +{ + unsigned ix; + + for (ix = 0; fname_vars[ix].decl; ix++) + if (fname_vars[ix].rid == rid) + break; + return fname_as_string (fname_vars[ix].pretty); +} + +/* Return the VAR_DECL for a const char array naming the current + function. If the VAR_DECL has not yet been created, create it + now. RID indicates how it should be formatted and IDENTIFIER_NODE + ID is its name (unfortunately C and C++ hold the RID values of + keywords in different places, so we can't derive RID from ID in + this language independant code. */ + +tree +fname_decl (rid, id) + unsigned rid; + tree id; +{ + unsigned ix; + tree decl = NULL_TREE; + + for (ix = 0; fname_vars[ix].decl; ix++) + if (fname_vars[ix].rid == rid) + break; + + decl = *fname_vars[ix].decl; + if (!decl) + { + tree saved_last_tree = last_tree; + + decl = (*make_fname_decl) (id, fname_vars[ix].pretty); + if (last_tree != saved_last_tree) + { + /* We created some statement tree for the decl. This belongs + at the start of the function, so remove it now and reinsert + it after the function is complete. */ + tree stmts = TREE_CHAIN (saved_last_tree); + + TREE_CHAIN (saved_last_tree) = NULL_TREE; + last_tree = saved_last_tree; + saved_function_name_decls = tree_cons (decl, stmts, + saved_function_name_decls); + } + *fname_vars[ix].decl = decl; } + if (!ix && !current_function_decl) + pedwarn_with_decl (decl, "`%s' is not defined outside of function scope"); - (*make_fname_decl) (function_id_node, name, 0); - (*make_fname_decl) (pretty_function_id_node, printable_name, 1); + return decl; } /* Given a chain of STRING_CST nodes, |