+2001-04-24 Zack Weinberg <zackw@stanford.edu>
+ Nathan Sidwell <nathan@codesourcery.com>
+
+ 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.
+
2001-04-24 Nick Clifton <nickc@cambridge.redhat.com>
* dwarf2out.c (mem_loc_descriptor): If a SYMBOL_REF is in the
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;
*/
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. */
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));
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,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_PTRBASE,
RID_PTREXTENT, RID_PTRVALUE,
+ /* Too many ways of getting the name of a function as a string */
+ RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
+
/* C++ */
RID_BOOL, RID_WCHAR, RID_CLASS,
RID_PUBLIC, RID_PRIVATE, RID_PROTECTED,
CTI_G77_LONGINT_TYPE,
CTI_G77_ULONGINT_TYPE,
- /* These are not types, but we have to look them up all the time. */
- CTI_FUNCTION_ID,
- CTI_PRETTY_FUNCTION_ID,
- CTI_FUNC_ID,
-
+ /* These are not types, but we have to look them up all the time. */
+ CTI_FUNCTION_NAME_DECL,
+ CTI_PRETTY_FUNCTION_NAME_DECL,
+ CTI_C99_FUNCTION_NAME_DECL,
+ CTI_SAVED_FUNCTION_NAME_DECLS,
+
CTI_VOID_ZERO,
CTI_MAX
#define g77_longint_type_node c_global_trees[CTI_G77_LONGINT_TYPE]
#define g77_ulongint_type_node c_global_trees[CTI_G77_ULONGINT_TYPE]
-#define function_id_node c_global_trees[CTI_FUNCTION_ID]
-#define pretty_function_id_node c_global_trees[CTI_PRETTY_FUNCTION_ID]
-#define func_id_node c_global_trees[CTI_FUNC_ID]
+#define function_name_decl_node c_global_trees[CTI_FUNCTION_NAME_DECL]
+#define pretty_function_name_decl_node c_global_trees[CTI_PRETTY_FUNCTION_NAME_DECL]
+#define c99_function_name_decl_node c_global_trees[CTI_C99_FUNCTION_NAME_DECL]
+#define saved_function_name_decls c_global_trees[CTI_SAVED_FUNCTION_NAME_DECLS]
/* A node for `((void) 0)'. */
#define void_zero_node c_global_trees[CTI_VOID_ZERO]
struct stmt_tree_s x_stmt_tree;
/* The stack of SCOPE_STMTs for the current function. */
tree x_scope_stmt_stack;
- /* Nonzero if __FUNCTION__ and its ilk have been declared in this
- function. */
- int x_function_name_declared_p;
};
/* When building a statement-tree, this is the last statement added to
what operator was specified for it. */
#define C_EXP_ORIGINAL_CODE(exp) ((enum tree_code) TREE_COMPLEXITY (exp))
-/* Pointer to function to generate the VAR_DECL for __FUNCTION__ etc.
+/* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc.
ID is the identifier to use, NAME is the string.
TYPE_DEP indicates whether it depends on type of the function or not
(i.e. __PRETTY_FUNCTION__). */
-extern tree (*make_fname_decl) PARAMS ((tree, const char *, int));
+extern tree (*make_fname_decl) PARAMS ((tree, int));
extern tree identifier_global_value PARAMS ((tree));
extern void record_builtin_type PARAMS ((enum rid,
const char *, tree));
extern tree build_void_list_node PARAMS ((void));
-
-extern void declare_function_name PARAMS ((void));
+extern void start_fname_decls PARAMS ((void));
+extern void finish_fname_decls PARAMS ((void));
+extern const char *fname_as_string PARAMS ((int));
+extern tree fname_decl PARAMS ((unsigned, tree));
+extern const char *fname_string PARAMS ((unsigned));
extern void decl_attributes PARAMS ((tree, tree, tree));
extern void init_function_format_info PARAMS ((void));
extern void check_function_format PARAMS ((int *, tree, tree, tree));
static tree c_scope_stmt_stack;
-/* Nonzero if __FUNCTION__ and its ilk have been declared in this
- function. */
-
-static int c_function_name_declared_p;
-
/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
that have names. Here so we can clear out their names' definitions
at the end of the function. */
int));
static tree grokparms PARAMS ((tree, int));
static void layout_array_type PARAMS ((tree));
-static tree c_make_fname_decl PARAMS ((tree, const char *, int));
+static tree c_make_fname_decl PARAMS ((tree, int));
static void c_expand_body PARAMS ((tree, int));
\f
/* C-specific option variables. */
pedantic_lvalues = pedantic;
- /* Create the global bindings for __FUNCTION__, __PRETTY_FUNCTION__,
- and __func__. */
- function_id_node = get_identifier ("__FUNCTION__");
- pretty_function_id_node = get_identifier ("__PRETTY_FUNCTION__");
- func_id_node = get_identifier ("__func__");
make_fname_decl = c_make_fname_decl;
- declare_function_name ();
+ start_fname_decls ();
start_identifier_warnings ();
are string merging candidates, which is wrong for C99's __func__. FIXME. */
static tree
-c_make_fname_decl (id, name, type_dep)
+c_make_fname_decl (id, type_dep)
tree id;
- const char *name;
- int type_dep ATTRIBUTE_UNUSED;
+ int type_dep;
{
+ const char *name = fname_as_string (type_dep);
tree decl, type, init;
size_t length = strlen (name);
type = build_array_type
(build_qualified_type (char_type_node, TYPE_QUAL_CONST),
- build_index_type (build_int_2 (length, 0)));
+ build_index_type (size_int (length)));
decl = build_decl (VAR_DECL, id, type);
+ /* We don't push the decl, so have to set its context here. */
+ DECL_CONTEXT (decl) = current_function_decl;
+
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
- TREE_ASM_WRITTEN (decl) = 1;
- DECL_SOURCE_LINE (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
- DECL_IN_SYSTEM_HEADER (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
+
init = build_string (length + 1, name);
TREE_TYPE (init) = type;
DECL_INITIAL (decl) = init;
- finish_decl (pushdecl (decl), init, NULL_TREE);
+
+ TREE_USED (decl) = 1;
+
+ finish_decl (decl, init, NULL_TREE);
return decl;
}
asmspec = TREE_STRING_POINTER (asmspec_tree);
/* If `start_decl' didn't like having an initialization, ignore it now. */
-
if (init != 0 && DECL_INITIAL (decl) == 0)
init = 0;
+
/* Don't crash if parm is initialized. */
if (TREE_CODE (decl) == PARM_DECL)
init = 0;
}
/* Deduce size of array from initialization, if not already known */
-
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) == 0
&& TREE_CODE (decl) != TYPE_DECL)
immediate_size_expand = old_immediate_size_expand;
+ start_fname_decls ();
+
return 1;
}
#endif
}
}
+
+ finish_fname_decls ();
/* Tie off the statement tree for this function. */
finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
function. For a nested function, this value is used in
pop_c_function_context and then reset via pop_function_context. */
current_function_decl = NULL;
- c_function_name_declared_p = 0;
}
}
p->base.x_stmt_tree = c_stmt_tree;
p->base.x_scope_stmt_stack = c_scope_stmt_stack;
- p->base.x_function_name_declared_p = c_function_name_declared_p;
p->named_labels = named_labels;
p->shadowed_labels = shadowed_labels;
p->returns_value = current_function_returns_value;
c_stmt_tree = p->base.x_stmt_tree;
c_scope_stmt_stack = p->base.x_scope_stmt_stack;
- c_function_name_declared_p = p->base.x_function_name_declared_p;
named_labels = p->named_labels;
shadowed_labels = p->shadowed_labels;
current_function_returns_value = p->returns_value;
/* Create the COMPOUND_STMT. */
stmt = add_stmt (build_stmt (COMPOUND_STMT, NULL_TREE));
- /* If we haven't already declared __FUNCTION__ and its ilk then this
- is the opening curly brace of the function. Declare them now. */
- if (!c_function_name_declared_p)
- {
- c_function_name_declared_p = 1;
- declare_function_name ();
- }
return stmt;
}
%token REALPART IMAGPART VA_ARG
%token PTR_VALUE PTR_BASE PTR_EXTENT
+/* function name can be a string const or a var decl. */
+%token STRING_FUNC_NAME VAR_FUNC_NAME
+
/* Add precedence rules to solve dangling else s/r conflict */
%nonassoc IF
%nonassoc ELSE
get us back to the global binding level. */
while (! global_bindings_p ())
poplevel (0, 0, 0);
- finish_file ();
+ifc
+ finish_fname_decls ();
+end ifc
+ finish_file ();
}
;
| CONSTANT
| string
{ $$ = combine_strings ($1); }
+ | VAR_FUNC_NAME
+ { $$ = fname_decl (C_RID_CODE ($$), $$); }
| '(' typename ')' '{'
{ start_init (NULL_TREE, NULL, 0);
$2 = groktypename ($2);
{
{ "_Bool", RID_BOOL, 0 },
{ "_Complex", RID_COMPLEX, 0 },
+ { "__FUNCTION__", RID_FUNCTION_NAME, 0 },
+ { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
{ "__alignof__", RID_ALIGNOF, 0 },
{ "__asm", RID_ASM, 0 },
{ "__const", RID_CONST, 0 },
{ "__const__", RID_CONST, 0 },
{ "__extension__", RID_EXTENSION, 0 },
+ { "__func__", RID_C99_FUNCTION_NAME, 0 },
{ "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 },
{ "__inline", RID_INLINE, 0 },
/* RID_PTREXTENT */ PTR_EXTENT,
/* RID_PTRVALUE */ PTR_VALUE,
+ /* RID_FUNCTION_NAME */ STRING_FUNC_NAME,
+ /* RID_PRETTY_FUNCTION_NAME */ STRING_FUNC_NAME,
+ /* RID_C99_FUNCTION_NAME */ VAR_FUNC_NAME,
+
/* C++ */
/* RID_BOOL */ TYPESPEC,
/* RID_WCHAR */ 0,
/* RID_BITAND */ 0,
/* RID_BITOR */ 0,
/* RID_COMPL */ 0,
-
+
/* Objective C */
/* RID_ID */ OBJECTNAME,
/* RID_AT_ENCODE */ ENCODE,
if (C_IS_RESERVED_WORD (yylval.ttype))
{
enum rid rid_code = C_RID_CODE (yylval.ttype);
+ int yycode = rid_to_yy[(int) rid_code];
+
+ if (yycode == STRING_FUNC_NAME)
+ {
+ /* __FUNCTION__ and __PRETTY_FUNCTION__ get converted
+ to string constants. */
+ const char *name = fname_string (rid_code);
+
+ yylval.ttype = build_string (strlen (name) + 1, name);
+ last_token = CPP_STRING; /* so yyerror won't choke */
+ return STRING;
+ }
+
/* Return the canonical spelling for this keyword. */
yylval.ttype = ridpointers[(int) rid_code];
- return rid_to_yy[(int) rid_code];
+ return yycode;
}
decl = lookup_name (yylval.ttype);
{
if (TREE_CODE (decl) == TYPE_DECL)
return TYPENAME;
- /* A user-invisible read-only initialized variable
- should be replaced by its value.
- We handle only strings since that's the only case used in C. */
- else if (TREE_CODE (decl) == VAR_DECL
- && DECL_IGNORED_P (decl)
- && TREE_READONLY (decl)
- && DECL_INITIAL (decl) != 0
- && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
- {
- tree stringval = DECL_INITIAL (decl);
-
- /* Copy the string value so that we won't clobber anything
- if we put something in the TREE_CHAIN of this one. */
- yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
- TREE_STRING_POINTER (stringval));
- return STRING;
- }
}
else if (doing_objc_thang)
{
variables and labels do not require any RTL generation. */
void (*lang_expand_decl_stmt) PARAMS ((tree));
-static tree prune_unused_decls PARAMS ((tree *, int *, void *));
-
/* Create an empty statement tree rooted at T. */
void
/* Add T to the statement-tree. */
TREE_CHAIN (last_tree) = t;
last_tree = t;
+
/* When we expand a statement-tree, we must know whether or not the
- statements are full-expresions. We record that fact here. */
+ statements are full-expressions. We record that fact here. */
STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
/* Keep track of the number of statements in this function. */
returns a new TREE_LIST representing the top of the SCOPE_STMT
stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is
zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT,
- and whose TREE_PURPOSE is the matching SCOPE_STMT iwth
+ and whose TREE_PURPOSE is the matching SCOPE_STMT with
SCOPE_BEGIN_P set. */
tree
return top;
}
-/* Remove declarations of internal variables that are not used from a
- stmt tree. To qualify, the variable must have a name and must have
- a zero DECL_SOURCE_LINE. We tried to remove all variables for
- which TREE_USED was false, but it turns out that there's tons of
- variables for which TREE_USED is false but that are still in fact
- used. */
-
-static tree
-prune_unused_decls (tp, walk_subtrees, data)
- tree *tp;
- int *walk_subtrees ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
-{
- tree t = *tp;
-
- if (t == NULL_TREE)
- return error_mark_node;
-
- if (TREE_CODE (t) == DECL_STMT)
- {
- tree d = DECL_STMT_DECL (t);
- if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
- {
- *tp = TREE_CHAIN (t);
- /* Recurse on the new value of tp, otherwise we will skip
- the next statement. */
- return prune_unused_decls (tp, walk_subtrees, data);
- }
- }
- else if (TREE_CODE (t) == SCOPE_STMT)
- {
- /* Remove all unused decls from the BLOCK of this SCOPE_STMT. */
- tree block = SCOPE_STMT_BLOCK (t);
-
- if (block)
- {
- tree *vp;
-
- for (vp = &BLOCK_VARS (block); *vp; )
- {
- tree v = *vp;
- if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
- *vp = TREE_CHAIN (v); /* drop */
- else
- vp = &TREE_CHAIN (v); /* advance */
- }
- /* If there are now no variables, the entire BLOCK can be dropped.
- (This causes SCOPE_NULLIFIED_P (t) to be true.) */
- if (BLOCK_VARS (block) == NULL_TREE)
- SCOPE_STMT_BLOCK (t) = NULL_TREE;
- }
- }
- return NULL_TREE;
-}
-
/* Finish the statement tree rooted at T. */
void
*t = stmt;
last_tree = NULL_TREE;
- /* Remove unused decls from the stmt tree. */
- walk_stmt_tree (t, prune_unused_decls, NULL);
-
if (cfun && stmt)
{
/* The line-number recorded in the outermost statement in a function
DECL_ANON_UNION_ELEMS (decl));
}
else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
- {
- if (DECL_ARTIFICIAL (decl) && ! TREE_USED (decl))
- /* Do not emit unused decls. This is not just an
- optimization. We really do not want to emit
- __PRETTY_FUNCTION__ etc, if they're never used. */
- DECL_IGNORED_P (decl) = 1;
- else
- make_rtl_for_local_static (decl);
- }
+ make_rtl_for_local_static (decl);
else if (TREE_CODE (decl) == LABEL_DECL
&& C_DECLARED_LABEL_FLAG (decl))
declare_nonlocal_label (decl);
+2001-04-24 Nathan Sidwell <nathan@codesourcery.com>
+
+ 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.
+
2001-04-24 Nathan Sidwell <nathan@codesourcery.com>
* pt.c (tsubst_decl): Use VOID_TYPE_P.
unused. */
DEFTREECODE (LOOKUP_EXPR, "lookup_expr", 'e', 1)
-/* Used to represent __PRETTY_FUNCTION__ in template bodies. */
-DEFTREECODE (FUNCTION_NAME, "function_name", 'e', 0)
-
/* A whole bunch of tree codes for the initial, superficial parsing of
templates. */
DEFTREECODE (MODOP_EXPR, "modop_expr", 'e', 3)
#define in_function_try_handler cp_function_chain->in_function_try_handler
-/* Nonzero if __FUNCTION__ and its ilk have been declared in this
- function. */
-
-#define function_name_declared_p \
- (cp_function_chain->base.x_function_name_declared_p)
-
extern tree current_function_return_value;
extern tree global_namespace;
extern tree declare_global_var PARAMS ((tree, tree));
extern void register_dtor_fn PARAMS ((tree));
extern tmpl_spec_kind current_tmpl_spec_kind PARAMS ((int));
+extern tree cp_fname_init PARAMS ((const char *));
/* in decl2.c */
extern void init_decl2 PARAMS ((void));
static tree get_dso_handle_node PARAMS ((void));
static tree start_cleanup_fn PARAMS ((void));
static void end_cleanup_fn PARAMS ((void));
-static tree cp_make_fname_decl PARAMS ((tree, const char *, int));
+static tree cp_make_fname_decl PARAMS ((tree, int));
static void initialize_predefined_identifiers PARAMS ((void));
static tree check_special_function_return_type
PARAMS ((special_function_kind, tree, tree));
{
tree bad_alloc_type_node, newtype, deltype;
+
if (flag_honor_std)
push_namespace (std_identifier);
bad_alloc_type_node = xref_tag
if (flag_honor_std)
pop_namespace ();
newtype = build_exception_variant
- (ptr_ftype_sizetype, add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1));
+ (ptr_ftype_sizetype, add_exception_specifier
+ (NULL_TREE, bad_alloc_type_node, -1));
deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
push_cp_library_fn (NEW_EXPR, newtype);
push_cp_library_fn (VEC_NEW_EXPR, newtype);
if (! supports_one_only ())
flag_weak = 0;
- /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
- function_id_node = get_identifier ("__FUNCTION__");
- pretty_function_id_node = get_identifier ("__PRETTY_FUNCTION__");
- func_id_node = get_identifier ("__func__");
-
make_fname_decl = cp_make_fname_decl;
- declare_function_name ();
+ start_fname_decls ();
/* Prepare to check format strings against argument lists. */
init_function_format_info ();
ggc_add_tree_root (&free_bindings, 1);
}
+/* Generate an initializer for a function naming variable from
+ NAME. NAME may be NULL, in which case we generate a special
+ ERROR_MARK node which should be replaced later. */
+
+tree
+cp_fname_init (name)
+ const char *name;
+{
+ tree domain = NULL_TREE;
+ tree type;
+ tree init = NULL_TREE;
+ size_t length = 0;
+
+ if (name)
+ {
+ length = strlen (name);
+ domain = build_index_type (size_int (length));
+ init = build_string (length + 1, name);
+ }
+
+ type = build_qualified_type (char_type_node, TYPE_QUAL_CONST);
+ type = build_cplus_array_type (type, domain);
+
+ if (init)
+ TREE_TYPE (init) = type;
+ else
+ /* We don't know the value until instantiation time. Make
+ something which will be digested now, but replaced later. */
+ init = build (ERROR_MARK, type);
+
+ return init;
+}
+
/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
decl, NAME is the initialization string and TYPE_DEP indicates whether
NAME depended on the type of the function. We make use of that to detect
- __PRETTY_FUNCTION__ inside a template fn. Because we build a tree for
- the function before emitting any of it, we don't need to treat the
- VAR_DECL specially. We can decide whether to emit it later, if it was
- used. */
+ __PRETTY_FUNCTION__ inside a template fn. This is being done
+ lazily at the point of first use, so we musn't push the decl now. */
static tree
-cp_make_fname_decl (id, name, type_dep)
+cp_make_fname_decl (id, type_dep)
tree id;
- const char *name;
int type_dep;
{
- tree decl, type, init;
- size_t length = strlen (name);
- tree domain = NULL_TREE;
-
- if (!processing_template_decl)
- type_dep = 0;
- if (!type_dep)
- domain = build_index_type (size_int (length));
-
- type = build_cplus_array_type
- (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
- domain);
+ const char *name = (type_dep && processing_template_decl
+ ? NULL : fname_as_string (type_dep));
+ tree init = cp_fname_init (name);
+ tree decl = build_decl (VAR_DECL, id, TREE_TYPE (init));
- decl = build_decl (VAR_DECL, id, type);
+ /* As we don't push the decl here, we must set the context. */
+ DECL_CONTEXT (decl) = current_function_decl;
+ DECL_PRETTY_FUNCTION_P (decl) = type_dep;
+
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
- DECL_SOURCE_LINE (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
- DECL_IN_SYSTEM_HEADER (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- pushdecl (decl);
- if (processing_template_decl)
- decl = push_template_decl (decl);
- if (type_dep)
- {
- init = build (FUNCTION_NAME, type);
- DECL_PRETTY_FUNCTION_P (decl) = 1;
- }
- else
- {
- init = build_string (length + 1, name);
- TREE_TYPE (init) = type;
- }
DECL_INITIAL (decl) = init;
- cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
+
+ TREE_USED (decl) = 1;
- /* We will have to make sure we only emit this, if it is actually used. */
+ cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
+
return decl;
}
if (scope && TREE_CODE (scope) == FUNCTION_DECL)
add_stmt (build_min (TAG_DEFN, enumtype));
+
return;
}
DECL_CONTEXT (dtor_label) = current_function_decl;
}
+ start_fname_decls ();
+
store_parm_decls (current_function_parms);
return 1;
my_friendly_assert (building_stmt_tree (), 20000911);
+ finish_fname_decls ();
+
/* For a cloned function, we've already got all the code we need;
there's no need to add any extra bits. */
if (!DECL_CLONED_FUNCTION_P (fndecl))
static const struct resword reswords[] =
{
{ "_Complex", RID_COMPLEX, 0 },
+ { "__FUNCTION__", RID_FUNCTION_NAME, 0 },
+ { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
{ "__alignof__", RID_ALIGNOF, 0 },
{ "__asm", RID_ASM, 0 },
{ "__const", RID_CONST, 0 },
{ "__const__", RID_CONST, 0 },
{ "__extension__", RID_EXTENSION, 0 },
+ { "__func__", RID_C99_FUNCTION_NAME, 0 },
{ "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 },
{ "__inline", RID_INLINE, 0 },
/* RID_PTREXTENT */ 0,
/* RID_PTRVALUE */ 0,
+ /* RID_FUNCTION_NAME */ VAR_FUNC_NAME,
+ /* RID_PRETTY_FUNCTION_NAME */ VAR_FUNC_NAME,
+ /* RID_c99_FUNCTION_NAME */ VAR_FUNC_NAME,
+
/* C++ */
/* RID_BOOL */ TYPESPEC,
/* RID_WCHAR */ TYPESPEC,
VARRAY_FREE (id.fns);
/* Now, expand this function into RTL, if appropriate. */
- function_name_declared_p = 1;
finish_function (0);
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
expand_body (clone);
yylval is the node for the constant. */
%token CONSTANT
+/* __func__, __FUNCTION__ or __PRETTY_FUNCTION__.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token VAR_FUNC_NAME
+
/* String constants in raw form.
yylval is a STRING_CST node. */
%token STRING
(TREE_TYPE (TREE_TYPE ($$)),
TYPE_DOMAIN (TREE_TYPE ($$)));
}
+ | VAR_FUNC_NAME
+ {
+ $$ = fname_decl (C_RID_CODE ($$), $$);
+ if (processing_template_decl)
+ $$ = build_min_nt (LOOKUP_EXPR, DECL_NAME ($$));
+ }
| '(' expr ')'
{ $$ = finish_parenthesized_expr ($2); }
| '(' expr_or_declarator_intern ')'
/* For __PRETTY_FUNCTION__ we have to adjust the initializer. */
if (DECL_PRETTY_FUNCTION_P (r))
{
- DECL_INITIAL (r) = tsubst (DECL_INITIAL (t),
- args,
- /*complain=*/1,
- NULL_TREE);
+ const char *name = (*decl_printable_name)
+ (current_function_decl, 2);
+ DECL_INITIAL (r) = cp_fname_init (name);
TREE_TYPE (r) = TREE_TYPE (DECL_INITIAL (r));
}
return TREE_TYPE (e1);
}
- case FUNCTION_NAME:
- {
- const char *name;
- int len;
- tree type;
- tree str;
-
- /* This code should match declare_hidden_char_array in
- c-common.c. */
- name = (*decl_printable_name) (current_function_decl, 2);
- len = strlen (name) + 1;
- type = build_array_type (char_type_node,
- build_index_type (size_int (len)));
- str = build_string (len, name);
- TREE_TYPE (str) = type;
- return str;
- }
-
default:
sorry ("use of `%s' in template",
tree_code_name [(int) TREE_CODE (t)]);
in_decl),
tsubst (TREE_TYPE (t), args, complain, in_decl));
- case FUNCTION_NAME:
- return tsubst (t, args, complain, in_decl);
-
default:
return t;
}
{
init = DECL_INITIAL (decl);
decl = tsubst (decl, args, complain, in_decl);
- init = tsubst_expr (init, args, complain, in_decl);
+ if (DECL_PRETTY_FUNCTION_P (decl))
+ init = DECL_INITIAL (decl);
+ else
+ init = tsubst_expr (init, args, complain, in_decl);
if (decl != error_mark_node)
{
if (TREE_CODE (decl) != TYPE_DECL)
/* Set up context. */
start_function (NULL_TREE, d, NULL_TREE, SF_PRE_PARSED);
- /* We already set up __FUNCTION__, etc., so we don't want to do
- it again now. */
- function_name_declared_p = 1;
-
/* Substitute into the body of the function. */
tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
/*complain=*/1, tmpl);
to accidentally keep a block *inside* the scopeless block. */
keep_next_level (0);
- /* If this is the outermost block of the function, declare the
- variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */
- if (cfun
- && !function_name_declared_p
- && !has_no_scope)
- {
- function_name_declared_p = 1;
- declare_function_name ();
- }
-
return r;
}
{
tree if_stmt;
tree compound_stmt;
- int saved_cfnd;
/* If the dtor is empty, and we know there is not any possible
way we could use any vtable entries, before they are possibly
finish_if_stmt_cond (boolean_true_node, if_stmt);
current_vcalls_possible_p = &IF_COND (if_stmt);
- /* Don't declare __PRETTY_FUNCTION__ and friends here when we
- open the block for the if-body. */
- saved_cfnd = function_name_declared_p;
- function_name_declared_p = 1;
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
- function_name_declared_p = saved_cfnd;
/* Make all virtual function table pointers in non-virtual base
classes point to CURRENT_CLASS_TYPE's virtual function
pop_everything ();
while (current_namespace != global_namespace)
pop_namespace ();
+
+ /* Do file scope __FUNCTION__ et al. */
+ finish_fname_decls ();
+
finish_file ();
}
genrtl_start_function (fn);
current_function_is_thunk = DECL_THUNK_P (fn);
- /* We don't need to redeclare __FUNCTION__, __PRETTY_FUNCTION__, or
- any of the other magic variables we set up when starting a
- function body. */
- function_name_declared_p = 1;
-
/* Expand the body. */
expand_stmt (DECL_SAVED_TREE (fn));
&& TREE_VALUE (init) == error_mark_node))
return error_mark_node;
+ if (TREE_CODE (init) == ERROR_MARK)
+ /* __PRETTY_FUNCTION__'s initializer is a bogus expression inside
+ a template function. This gets substituted during instantiation. */
+ return init;
+
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
if (TREE_CODE (init) == NON_LVALUE_EXPR)
init = TREE_OPERAND (init, 0);
+2001-04-24 Nathan Sidwell <nathan@codesourcery.com>
+
+ * gcc.dg/c99-func-2.c: Remove xfail.
+ * gcc.dg/c99-func-3.c: Remove xfail.
+ * gcc.dg/c99-func-4.c: Remove xfail.
+
2001-04-23 Zack Weinberg <zackw@stanford.edu>
* gcc.c-torture/execute/20010124-1.c: No longer expected to fail.
void
foo (void)
{
- __func__ "foo"; /* { dg-bogus "warning" "warning in place of error" } */
- /* { dg-error "parse error" "__func__ not string constant" { xfail *-*-* } 9 } */
+ __func__ "foo"; /* { dg-error "parse error" "before string constant" } */
}
/* Test for C99 __func__: not merging with string literals. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do run { xfail *-*-* } } */
+/* { dg-do run } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
extern void abort (void);
void
foo (void)
{
- char *p = __func__; /* { dg-error "discards" "__func__ pointer to const" { xfail *-*-* } } */
+ char *p = __func__; /* { dg-error "discards" "__func__ pointer to const" } */
}