#include "diagnostic.h"
#include "debug.h"
#include "timevar.h"
+#include "tree-flow.h"
-static tree grokparms (tree);
+static tree grokparms (tree, tree *);
static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
static int unary_op_p (enum tree_code);
static void push_local_name (tree);
static tree grok_reference_init (tree, tree, tree, tree *);
-static tree grokfndecl (tree, tree, tree, tree, int,
+static tree grokfndecl (tree, tree, tree, tree, tree, int,
enum overload_flags, tree,
tree, int, int, int, int, int, int, tree);
static tree grokvardecl (tree, tree, RID_BIT_TYPE *, int, int, tree);
static tree push_cp_library_fn (enum tree_code, tree);
static tree build_cp_library_fn (tree, enum tree_code, tree);
static void store_parm_decls (tree);
-static int cp_missing_noreturn_ok_p (tree);
static void initialize_local_var (tree, tree);
static void expand_static_init (tree, tree);
static tree next_initializable_field (tree);
tree integer_two_node, integer_three_node;
-/* Similar, for last_function_parm_tags. */
-tree last_function_parms;
-
/* A list 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, and so we can check the validity of jumps to these labels. */
else
decls = current_binding_level->names;
- /* Output any nested inline functions within this block
- if they weren't already output. */
- for (decl = decls; decl; decl = TREE_CHAIN (decl))
- if (TREE_CODE (decl) == FUNCTION_DECL
- && ! TREE_ASM_WRITTEN (decl)
- && DECL_INITIAL (decl) != NULL_TREE
- && TREE_ADDRESSABLE (decl)
- && decl_function_context (decl) == current_function_decl)
- {
- /* If this decl was copied from a file-scope decl
- on account of a block-scope extern decl,
- propagate TREE_ADDRESSABLE to the file-scope decl. */
- if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
- TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
- else
- {
- push_function_context ();
- output_inline_function (decl);
- pop_function_context ();
- }
- }
-
/* When not in function-at-a-time mode, expand_end_bindings will
warn about unused variables. But, in function-at-a-time mode
expand_end_bindings is not passed the list of variables in the
DECL_SOURCE_LOCATION (olddecl)
= DECL_SOURCE_LOCATION (DECL_TEMPLATE_RESULT (olddecl))
= DECL_SOURCE_LOCATION (newdecl);
+ if (DECL_FUNCTION_TEMPLATE_P (newdecl))
+ DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (olddecl))
+ = DECL_ARGUMENTS (DECL_TEMPLATE_RESULT (newdecl));
}
if (DECL_FUNCTION_TEMPLATE_P (newdecl))
/* You can't use labels at global scope. */
if (current_function_decl == NULL_TREE)
{
- error ("label `%s' referenced outside of any function",
- IDENTIFIER_POINTER (id));
+ error ("label `%E' referenced outside of any function", id);
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
}
void
pop_switch (void)
{
- struct cp_switch *cs;
+ struct cp_switch *cs = switch_stack;
+
+ /* Emit warnings as needed. */
+ c_do_switch_warnings (cs->cases, cs->switch_stmt);
- cs = switch_stack;
splay_tree_delete (cs->cases);
switch_stack = switch_stack->next;
free (cs);
/* Create all the identifiers we need. */
initialize_predefined_identifiers ();
- /* Fill in back-end hooks. */
- lang_missing_noreturn_ok_p = &cp_missing_noreturn_ok_p;
-
/* Create the global variables. */
push_to_top_level ();
start_fname_decls ();
/* Show we use EH for cleanups. */
- using_eh_for_cleanups ();
+ if (flag_exceptions)
+ using_eh_for_cleanups ();
}
/* Generate an initializer for a function naming variable from
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. This is being done
- lazily at the point of first use, so we musn't push the decl now. */
+ lazily at the point of first use, so we mustn't push the decl now. */
static tree
cp_make_fname_decl (tree id, int type_dep)
tree init = cp_fname_init (name, &type);
tree decl = build_decl (VAR_DECL, id, type);
+ if (name)
+ free ((char *) name);
+
/* As we're using pushdecl_with_scope, we must set the context. */
DECL_CONTEXT (decl) = current_function_decl;
DECL_PRETTY_FUNCTION_P (decl) = type_dep;
else
{
tree field = check_classfn (context, decl,
- processing_template_decl
- > template_class_depth (context));
+ (processing_template_decl
+ > template_class_depth (context))
+ ? current_template_parms
+ : NULL_TREE);
if (field && duplicate_decls (decl, field))
decl = field;
}
if (type == error_mark_node)
return;
- maybe_push_cleanup_level (type);
-
if (initialized)
/* Is it valid for this decl to have an initializer at all?
If not, set INITIALIZED to zero, which will indirectly
if (! initialized)
DECL_INITIAL (decl) = NULL_TREE;
+
+ /* Create a new scope to hold this declaration if necessary.
+ Whether or not a new scope is necessary cannot be determined
+ until after the type has been completed; if the type is a
+ specialization of a class template it is not until after
+ instantiation has occurred that TYPE_HAS_NONTRIVIAL_DESTRUCTOR
+ will be set correctly. */
+ maybe_push_cleanup_level (type);
}
/* Handle initialization of references. DECL, TYPE, and INIT have the
enclosed elements. Advance past the brace-enclosed initializer
now. */
if (TREE_CODE (old_init_value) == CONSTRUCTOR
- && TREE_TYPE (old_init_value) == NULL_TREE
- && TREE_HAS_CONSTRUCTOR (old_init_value))
+ && BRACE_ENCLOSED_INITIALIZER_P (old_init_value))
{
*initp = TREE_CHAIN (old_init);
TREE_CHAIN (old_init) = NULL_TREE;
else
{
/* Build a CONSTRUCTOR to hold the contents of the aggregate. */
- new_init = build_constructor (type, NULL_TREE);
- TREE_HAS_CONSTRUCTOR (new_init) = 1;
+ new_init = build_constructor (NULL_TREE, NULL_TREE);
if (CLASS_TYPE_P (type))
{
}
}
}
- else if ((TREE_CODE (type) == ARRAY_TYPE)|| (TREE_CODE (type) == VECTOR_TYPE))
+ else if (TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE)
{
tree index;
tree max_index;
/* If the bound of the array is known, take no more initializers
than are allowed. */
- max_index = ((TYPE_DOMAIN (type) && (TREE_CODE (type) == ARRAY_TYPE))
- ? array_type_nelts (type) : NULL_TREE);
+ max_index = NULL_TREE;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (TYPE_DOMAIN (type))
+ max_index = array_type_nelts (type);
+ }
+ else
+ {
+ /* For a vector, the representation type is a struct
+ containing a single member which is an array of the
+ appropriate size. */
+ tree rtype = TYPE_DEBUG_REPRESENTATION_TYPE (type);
+ if (rtype && TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (rtype))))
+ max_index = array_type_nelts (TREE_TYPE (TYPE_FIELDS (rtype)));
+ }
+
/* Loop through the array elements, gathering initializers. */
for (index = size_zero_node;
*initp && (!max_index || !tree_int_cst_lt (max_index, index));
init = grok_reference_init (decl, type, init, cleanup);
else if (init)
{
- if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+ if (TREE_CODE (init) == CONSTRUCTOR
+ && BRACE_ENCLOSED_INITIALIZER_P (init))
{
/* [dcl.init] paragraph 13,
If T is a scalar type, then a declaration of the form
array size from the initializer. */
maybe_deduce_size_from_array_init (decl, init);
type = TREE_TYPE (decl);
- if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
- TREE_TYPE (init) = type;
if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
{
if (TREE_CODE (type) == ARRAY_TYPE)
goto initialize_aggr;
else if (TREE_CODE (init) == CONSTRUCTOR
- && TREE_HAS_CONSTRUCTOR (init))
+ && BRACE_ENCLOSED_INITIALIZER_P (init))
{
if (TYPE_NON_AGGREGATE_CLASS (type))
{
asm-specification, indicates that the variable should be
placed in a particular register. */
if (DECL_REGISTER (decl))
- DECL_C_HARD_REGISTER (decl) = 1;
+ DECL_HARD_REGISTER (decl) = 1;
}
/* We don't create any RTL for local variables. */
if (init && DECL_INITIAL (decl))
DECL_INITIAL (decl) = init;
+ if (TREE_CODE (decl) == VAR_DECL
+ && !DECL_PRETTY_FUNCTION_P (decl)
+ && !dependent_type_p (TREE_TYPE (decl)))
+ maybe_deduce_size_from_array_init (decl, init);
goto finish_end0;
}
if (TREE_CODE (decl) != FUNCTION_DECL)
ttype = target_type (type);
- if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl)
- && (TYPE_NEEDS_CONSTRUCTING (type)
- || TREE_CODE (type) == REFERENCE_TYPE))
+
+ /* Currently, GNU C++ puts constants in text space, making them
+ impossible to initialize. In the future, one would hope for
+ an operating system which understood the difference between
+ initialization and the running of a program. */
+ if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl))
{
- /* Currently, GNU C++ puts constants in text space, making them
- impossible to initialize. In the future, one would hope for
- an operating system which understood the difference between
- initialization and the running of a program. */
was_readonly = 1;
- TREE_READONLY (decl) = 0;
+ if (TYPE_NEEDS_CONSTRUCTING (type)
+ || TREE_CODE (type) == REFERENCE_TYPE)
+ TREE_READONLY (decl) = 0;
}
if (TREE_CODE (decl) == VAR_DECL)
/* If this was marked 'used', be sure it will be output. */
if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
- mark_referenced (DECL_ASSEMBLER_NAME (decl));
+ mark_decl_referenced (decl);
}
/* This is here for a midend callback from c-common.c. */
{
tree itype;
tree domain;
+ tree elt_type;
domain = build_index_type (maxindex);
TYPE_DOMAIN (type) = domain;
size of the array. */
if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)))
TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = domain;
+
+ elt_type = TREE_TYPE (type);
+ TYPE_NEEDS_CONSTRUCTING (type)
+ = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
+ TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
}
/* Lay out the type now that we can get the real answer. */
TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
or METHOD_TYPE.
DECLARATOR is the function's name.
+ PARMS is a chain of PARM_DECLs for the function.
VIRTUALP is truthvalue of whether the function is virtual or not.
FLAGS are to be passed through to `grokclassfn'.
QUALS are qualifiers indicating whether the function is `const'
grokfndecl (tree ctype,
tree type,
tree declarator,
+ tree parms,
tree orig_declarator,
int virtualp,
enum overload_flags flags,
type = build_exception_variant (type, raises);
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
+ DECL_ARGUMENTS (decl) = parms;
/* Propagate volatile out from type to decl. */
if (TYPE_VOLATILE (type))
TREE_THIS_VOLATILE (decl) = 1;
tree old_decl;
old_decl = check_classfn (ctype, decl,
- processing_template_decl
- > template_class_depth (ctype));
+ (processing_template_decl
+ > template_class_depth (ctype))
+ ? current_template_parms
+ : NULL_TREE);
if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
/* Because grokfndecl is always supposed to return a
if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
- {
- /* Remove the `this' parm added by grokclassfn.
- XXX Isn't this done in start_function, too? */
- revert_static_member_fn (decl);
- last_function_parms = TREE_CHAIN (last_function_parms);
- }
+ /* Remove the `this' parm added by grokclassfn.
+ XXX Isn't this done in start_function, too? */
+ revert_static_member_fn (decl);
if (old_decl && DECL_ARTIFICIAL (old_decl))
error ("definition of implicitly-declared `%D'", old_decl);
tree in_namespace = NULL_TREE;
tree returned_attrs = NULL_TREE;
tree scope = NULL_TREE;
+ tree parms = NULL_TREE;
RIDBIT_RESET_ALL (specbits);
if (decl_context == FUNCDEF)
longlong = 1;
}
else if (RIDBIT_SETP (i, specbits))
- pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
+ pedwarn ("duplicate `%E'", id);
/* Diagnose "__thread extern" or "__thread static". */
if (RIDBIT_SETP (RID_THREAD, specbits))
{
tree t = lookup_name (id, 1);
if (!t || TREE_CODE (t) != TYPE_DECL)
- error ("`%s' fails to be a typedef or built in type",
- IDENTIFIER_POINTER (id));
+ error ("`%E' fails to be a typedef or built in type", id);
else
{
type = TREE_TYPE (t);
type = create_array_type_for_decl (dname, type, size);
+ if (declarator
+ && (TREE_CODE (declarator) == INDIRECT_REF
+ || TREE_CODE (declarator) == ADDR_EXPR))
+ /* We can never complete an array type which is the target of a
+ pointer, so go ahead and lay it out. */
+ layout_type (type);
+
ctype = NULL_TREE;
}
break;
error ("destructor cannot be static member function");
if (quals)
{
- error ("destructors may not be `%s'",
- IDENTIFIER_POINTER (TREE_VALUE (quals)));
+ error ("destructors may not be `%E'",
+ TREE_VALUE (quals));
quals = NULL_TREE;
}
if (decl_context == FIELD)
}
if (quals)
{
- error ("constructors may not be `%s'",
- IDENTIFIER_POINTER (TREE_VALUE (quals)));
+ error ("constructors may not be `%E'",
+ TREE_VALUE (quals));
quals = NULL_TREE;
}
{
declarator = TREE_OPERAND (declarator, 0);
- arg_types = grokparms (inner_parms);
+ arg_types = grokparms (inner_parms, &parms);
if (declarator && flags == DTOR_FLAG)
{
{
error ("destructors may not have parameters");
arg_types = void_list_node;
- last_function_parms = NULL_TREE;
+ parms = NULL_TREE;
}
}
}
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
- if (current_class_type == NULL_TREE || friendp)
+ if (NEW_DELETE_OPNAME_P (sname))
+ /* Overloaded operator new and operator delete
+ are always static functions. */
+ ;
+ else if (current_class_type == NULL_TREE || friendp)
type
= build_method_type_directly (ctype,
TREE_TYPE (type),
}
if (declarator == NULL_TREE
+ || TREE_CODE (declarator) == ERROR_MARK
|| TREE_CODE (declarator) == IDENTIFIER_NODE
|| (TREE_CODE (declarator) == TEMPLATE_ID_EXPR
&& (TREE_CODE (type) == FUNCTION_TYPE
type = build_cplus_array_type (TREE_TYPE (type), NULL_TREE);
/* Detect where we're using a typedef of function type to declare a
- function. last_function_parms will not be set, so we must create
- it now. */
+ function. PARMS will not be set, so we must create it now. */
if (type == typedef_type && TREE_CODE (type) == FUNCTION_TYPE)
{
decls = decl;
}
- last_function_parms = nreverse (decls);
+ parms = nreverse (decls);
}
/* If this is a type name (such as, in a cast or sizeof),
return void_type_node;
}
- if (declarator == ansi_opname (NEW_EXPR)
- || declarator == ansi_opname (VEC_NEW_EXPR)
- || declarator == ansi_opname (DELETE_EXPR)
- || declarator == ansi_opname (VEC_DELETE_EXPR))
+ if (NEW_DELETE_OPNAME_P (declarator))
{
if (virtualp)
{
decl = grokfndecl (ctype, type,
TREE_CODE (declarator) != TEMPLATE_ID_EXPR
? declarator : dname,
+ parms,
declarator,
virtualp, flags, quals, raises,
friendp ? -1 : 0, friendp, publicp, inlinep,
decl = grokfndecl (ctype, type,
TREE_CODE (declarator) != TEMPLATE_ID_EXPR
? declarator : dname,
+ parms,
declarator,
virtualp, flags, quals, raises,
friendp ? -1 : 0, friendp, 1, 0, funcdef_flag,
{
if (friendp)
{
- error ("`%s' is neither function nor member function; cannot be declared friend",
- IDENTIFIER_POINTER (declarator));
+ error ("`%E' is neither function nor member function; "
+ "cannot be declared friend", declarator);
friendp = 0;
}
decl = NULL_TREE;
}
decl = do_friend (ctype, declarator, decl,
- last_function_parms, *attrlist,
- flags, quals, funcdef_flag);
+ *attrlist, flags, quals, funcdef_flag);
return decl;
}
else
virtualp = 0;
}
}
- else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
+ else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2
+ && !NEW_DELETE_OPNAME_P (original_name))
type = build_method_type_directly (ctype,
TREE_TYPE (type),
TYPE_ARG_TYPES (type));
|| RIDBIT_SETP (RID_EXTERN, specbits)
|| !RIDBIT_SETP (RID_STATIC, specbits));
- decl = grokfndecl (ctype, type, original_name, declarator,
+ decl = grokfndecl (ctype, type, original_name, parms, declarator,
virtualp, flags, quals, raises,
1, friendp,
publicp, inlinep, funcdef_flag,
flag. If unset, we append void_list_node. A parmlist declared
as `(void)' is accepted as the empty parmlist.
- Also set last_function_parms to the chain of PARM_DECLs. */
+ *PARMS is set to the chain of PARM_DECLs created. */
static tree
-grokparms (tree first_parm)
+grokparms (tree first_parm, tree *parms)
{
tree result = NULL_TREE;
tree decls = NULL_TREE;
result = nreverse (result);
if (!ellipsis)
result = chainon (result, void_list_node);
- last_function_parms = decls;
+ *parms = decls;
return result;
}
}
if (operator_code == NEW_EXPR || operator_code == VEC_NEW_EXPR)
- {
- /* When the compiler encounters the definition of A::operator new, it
- doesn't look at the class declaration to find out if it's static. */
- if (methodp)
- revert_static_member_fn (decl);
-
- TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
- }
+ TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
else if (operator_code == DELETE_EXPR || operator_code == VEC_DELETE_EXPR)
- {
- if (methodp)
- revert_static_member_fn (decl);
-
- TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
- }
+ TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
else
{
/* An operator function must either be a non-static member function
{
if (!globalize && processing_template_decl && IS_AGGR_TYPE (t))
redeclare_class_template (t, current_template_parms);
+ else if (!processing_template_decl
+ && CLASS_TYPE_P (t)
+ && CLASSTYPE_IS_TEMPLATE (t))
+ {
+ error ("redeclaration of `%T' as a non-template", t);
+ t = error_mark_node;
+ }
}
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
{
underlying_type = integer_types[itk];
if (TYPE_PRECISION (underlying_type) >= precision
- && TREE_UNSIGNED (underlying_type) == unsignedp)
+ && TYPE_UNSIGNED (underlying_type) == unsignedp)
break;
}
if (itk == itk_none)
TYPE_MODE (enumtype) = TYPE_MODE (underlying_type);
TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type);
TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type);
- TREE_UNSIGNED (enumtype) = TREE_UNSIGNED (underlying_type);
+ TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (underlying_type);
/* Convert each of the enumerators to the type of the underlying
type of the enumeration. */
TYPE_PRECISION (t) = TYPE_PRECISION (enumtype);
TYPE_ALIGN (t) = TYPE_ALIGN (enumtype);
TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (enumtype);
- TREE_UNSIGNED (t) = TREE_UNSIGNED (enumtype);
+ TYPE_UNSIGNED (t) = TYPE_UNSIGNED (enumtype);
}
/* Finish debugging output for this type. */
decl = build_decl (CONST_DECL, name, type);
DECL_CONTEXT (decl) = FROB_CONTEXT (context);
- TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1;
+ TREE_CONSTANT (decl) = 1;
+ TREE_INVARIANT (decl) = 1;
+ TREE_READONLY (decl) = 1;
DECL_INITIAL (decl) = value;
if (context && context == current_class_type)
else
doing_friend = 1;
}
-
- last_function_parms = DECL_ARGUMENTS (decl1);
}
else
{
&& TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
{
revert_static_member_fn (decl1);
- last_function_parms = TREE_CHAIN (last_function_parms);
ctype = NULL_TREE;
}
/* Save the parm names or decls from this function's declarator
where store_parm_decls will find them. */
- current_function_parms = last_function_parms;
+ current_function_parms = DECL_ARGUMENTS (decl1);
/* Make sure the parameter and return types are reasonable. When
you declare a function, these types can be incomplete, but they
of curly braces for a function. */
my_friendly_assert (stmts_are_full_exprs_p (), 19990831);
- /* Set up the named return value optimization, if we can. Here, we
- eliminate the copy from the nrv into the RESULT_DECL and any cleanup
- for the nrv. genrtl_start_function and declare_return_variable
- handle making the nrv and RESULT_DECL share space. */
+ /* Set up the named return value optimization, if we can. Candidate
+ variables are selected in check_return_value. */
if (current_function_return_value)
{
tree r = current_function_return_value;
/* Skip the artificial function body block. */
&& (outer = BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl))),
chain_member (r, BLOCK_VARS (outer))))
- {
-
- DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fndecl));
- walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
- nullify_returns_r, r);
- }
- else
- /* Clear it so genrtl_start_function and declare_return_variable
- know we're not optimizing. */
- current_function_return_value = NULL_TREE;
+ finalize_nrv (&DECL_SAVED_TREE (fndecl), r, DECL_RESULT (fndecl));
+
+ current_function_return_value = NULL_TREE;
}
/* Remember that we were in class scope. */
if (!processing_template_decl)
save_function_data (fndecl);
- /* If this function calls `setjmp' it cannot be inlined. When
- `longjmp' is called it is not guaranteed to restore the value of
- local variables that have been modified since the call to
- `setjmp'. So, if were to inline this function into some caller
- `c', then when we `longjmp', we might not restore all variables
- in `c'. (It might seem, at first blush, that there's no way for
- this function to modify local variables in `c', but their
- addresses may have been stored somewhere accessible to this
- function.) */
- if (!processing_template_decl && calls_setjmp_p (fndecl))
- DECL_UNINLINABLE (fndecl) = 1;
-
/* Complain if there's just no return statement. */
if (warn_return_type
&& TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE
&& (DECL_INLINE (fndecl) || processing_template_decl))
warning ("no return statement in function returning non-void");
- /* We're leaving the context of this function, so zap cfun.
- It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
- tree_rest_of_compilation. */
+ /* Store the end of the function, so that we get good line number
+ info for the epilogue. */
+ cfun->function_end_locus = input_location;
+
+ /* Genericize before inlining. */
+ if (!processing_template_decl)
+ {
+ c_genericize (fndecl);
+
+ /* Handle attribute((warn_unused_result)). Relies on gimple input. */
+ c_warn_unused_result (&DECL_SAVED_TREE (fndecl));
+ }
+
+ /* We're leaving the context of this function, so zap cfun. It's still in
+ DECL_STRUCT_FUNCTION, and we'll restore it in tree_rest_of_compilation. */
cfun = NULL;
current_function_decl = NULL;
return t;
}
-static int
+bool
cp_missing_noreturn_ok_p (tree decl)
{
/* A missing noreturn is ok for the `main' function. */