Merge our -fformat-extensions and printf0() into GCC 2.95.1.
This commit is contained in:
parent
fa8af026d5
commit
1850ef0c96
@ -1,5 +1,5 @@
|
||||
/* Subroutines shared by all languages that are variants of C.
|
||||
Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
@ -18,6 +18,8 @@ along with GNU CC; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "tree.h"
|
||||
@ -27,6 +29,8 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "obstack.h"
|
||||
#include "toplev.h"
|
||||
#include "output.h"
|
||||
#include "c-pragma.h"
|
||||
#include "rtl.h"
|
||||
|
||||
#if USE_CPPLIB
|
||||
#include "cpplib.h"
|
||||
@ -50,19 +54,22 @@ extern struct obstack permanent_obstack;
|
||||
int skip_evaluation;
|
||||
|
||||
enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
|
||||
A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
|
||||
A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
|
||||
A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
|
||||
|
||||
enum format_type { printf_format_type, scanf_format_type,
|
||||
strftime_format_type };
|
||||
|
||||
static void declare_hidden_char_array PROTO((char *, char *));
|
||||
static void add_attribute PROTO((enum attrs, char *,
|
||||
static void declare_hidden_char_array PROTO((const char *, const char *));
|
||||
static void add_attribute PROTO((enum attrs, const char *,
|
||||
int, int, int));
|
||||
static void init_attributes PROTO((void));
|
||||
static void record_function_format PROTO((tree, tree, enum format_type,
|
||||
int, int, int));
|
||||
static void record_international_format PROTO((tree, tree, int));
|
||||
static tree c_find_base_decl PROTO((tree));
|
||||
static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree));
|
||||
|
||||
/* Keep a stack of if statements. We record the number of compound
|
||||
statements seen up to the if keyword, as well as the line number
|
||||
@ -73,9 +80,10 @@ typedef struct
|
||||
{
|
||||
int compstmt_count;
|
||||
int line;
|
||||
char *file;
|
||||
const char *file;
|
||||
int needs_warning;
|
||||
} if_elt;
|
||||
static void tfaff PROTO((void));
|
||||
|
||||
static if_elt *if_stack;
|
||||
|
||||
@ -153,12 +161,12 @@ c_expand_start_else ()
|
||||
expand_start_else ();
|
||||
}
|
||||
|
||||
/* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
|
||||
/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__. */
|
||||
|
||||
void
|
||||
declare_function_name ()
|
||||
{
|
||||
char *name, *printable_name;
|
||||
const char *name, *printable_name;
|
||||
|
||||
if (current_function_decl == NULL)
|
||||
{
|
||||
@ -177,11 +185,14 @@ declare_function_name ()
|
||||
|
||||
declare_hidden_char_array ("__FUNCTION__", name);
|
||||
declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name);
|
||||
/* The ISO C people "of course" couldn't use __FUNCTION__ in the
|
||||
ISO C 9x standard; instead a new variable is invented. */
|
||||
declare_hidden_char_array ("__func__", name);
|
||||
}
|
||||
|
||||
static void
|
||||
declare_hidden_char_array (name, value)
|
||||
char *name, *value;
|
||||
const char *name, *value;
|
||||
{
|
||||
tree decl, type, init;
|
||||
int vlen;
|
||||
@ -262,7 +273,7 @@ combine_strings (strings)
|
||||
? wchar_bytes : 1));
|
||||
if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
|
||||
{
|
||||
bcopy (TREE_STRING_POINTER (t), q, len);
|
||||
memcpy (q, TREE_STRING_POINTER (t), len);
|
||||
q += len;
|
||||
}
|
||||
else
|
||||
@ -290,7 +301,6 @@ combine_strings (strings)
|
||||
value = make_node (STRING_CST);
|
||||
TREE_STRING_POINTER (value) = p;
|
||||
TREE_STRING_LENGTH (value) = length;
|
||||
TREE_CONSTANT (value) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -305,8 +315,9 @@ combine_strings (strings)
|
||||
|
||||
/* Create the array type for the string constant.
|
||||
-Wwrite-strings says make the string constant an array of const char
|
||||
so that copying it to a non-const pointer will get a warning. */
|
||||
if (warn_write_strings
|
||||
so that copying it to a non-const pointer will get a warning.
|
||||
For C++, this is the standard behavior. */
|
||||
if (flag_const_strings
|
||||
&& (! flag_traditional && ! flag_writable_strings))
|
||||
{
|
||||
tree elements
|
||||
@ -320,7 +331,8 @@ combine_strings (strings)
|
||||
TREE_TYPE (value)
|
||||
= build_array_type (wide_flag ? wchar_type_node : char_type_node,
|
||||
build_index_type (build_int_2 (nchars - 1, 0)));
|
||||
TREE_CONSTANT (value) = 1;
|
||||
|
||||
TREE_READONLY (value) = TREE_CONSTANT (value) = ! flag_writable_strings;
|
||||
TREE_STATIC (value) = 1;
|
||||
return value;
|
||||
}
|
||||
@ -339,7 +351,7 @@ static int attrtab_idx = 0;
|
||||
static void
|
||||
add_attribute (id, string, min_len, max_len, decl_req)
|
||||
enum attrs id;
|
||||
char *string;
|
||||
const char *string;
|
||||
int min_len, max_len;
|
||||
int decl_req;
|
||||
{
|
||||
@ -382,8 +394,29 @@ init_attributes ()
|
||||
add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
|
||||
add_attribute (A_WEAK, "weak", 0, 0, 1);
|
||||
add_attribute (A_ALIAS, "alias", 1, 1, 1);
|
||||
add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
|
||||
add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
|
||||
}
|
||||
|
||||
/* Default implementation of valid_lang_attribute, below. By default, there
|
||||
are no language-specific attributes. */
|
||||
|
||||
static int
|
||||
default_valid_lang_attribute (attr_name, attr_args, decl, type)
|
||||
tree attr_name ATTRIBUTE_UNUSED;
|
||||
tree attr_args ATTRIBUTE_UNUSED;
|
||||
tree decl ATTRIBUTE_UNUSED;
|
||||
tree type ATTRIBUTE_UNUSED;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid language-specific
|
||||
attribute for either declaration DECL or type TYPE and 0 otherwise. */
|
||||
|
||||
int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree))
|
||||
= default_valid_lang_attribute;
|
||||
|
||||
/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
|
||||
and install them in NODE, which is either a DECL (including a TYPE_DECL)
|
||||
or a TYPE. PREFIX_ATTRIBUTES can appear after the declaration specifiers
|
||||
@ -409,6 +442,18 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't')
|
||||
type = node, is_type = 1;
|
||||
|
||||
#ifdef PRAGMA_INSERT_ATTRIBUTES
|
||||
/* If the code in c-pragma.c wants to insert some attributes then
|
||||
allow it to do so. Do this before allowing machine back ends to
|
||||
insert attributes, so that they have the opportunity to override
|
||||
anything done here. */
|
||||
PRAGMA_INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
|
||||
#endif
|
||||
|
||||
#ifdef INSERT_ATTRIBUTES
|
||||
INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
|
||||
#endif
|
||||
|
||||
attributes = chainon (prefix_attributes, attributes);
|
||||
|
||||
for (a = attributes; a; a = TREE_CHAIN (a))
|
||||
@ -424,7 +469,8 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
|
||||
if (i == attrtab_idx)
|
||||
{
|
||||
if (! valid_machine_attribute (name, args, decl, type))
|
||||
if (! valid_machine_attribute (name, args, decl, type)
|
||||
&& ! (* valid_lang_attribute) (name, args, decl, type))
|
||||
warning ("`%s' attribute directive ignored",
|
||||
IDENTIFIER_POINTER (name));
|
||||
else if (decl != 0)
|
||||
@ -491,7 +537,8 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
TREE_USED (type) = 1;
|
||||
else if (TREE_CODE (decl) == PARM_DECL
|
||||
|| TREE_CODE (decl) == VAR_DECL
|
||||
|| TREE_CODE (decl) == FUNCTION_DECL)
|
||||
|| TREE_CODE (decl) == FUNCTION_DECL
|
||||
|| TREE_CODE (decl) == LABEL_DECL)
|
||||
TREE_USED (decl) = 1;
|
||||
else
|
||||
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
|
||||
@ -555,7 +602,7 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
else
|
||||
{
|
||||
int j;
|
||||
char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
|
||||
const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
|
||||
int len = strlen (p);
|
||||
enum machine_mode mode = VOIDmode;
|
||||
tree typefm;
|
||||
@ -633,7 +680,7 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
= (args ? TREE_VALUE (args)
|
||||
: size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
|
||||
int align;
|
||||
|
||||
|
||||
/* Strip any NOPs of any kind. */
|
||||
while (TREE_CODE (align_expr) == NOP_EXPR
|
||||
|| TREE_CODE (align_expr) == CONVERT_EXPR
|
||||
@ -688,7 +735,7 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
}
|
||||
else
|
||||
{
|
||||
char *p = IDENTIFIER_POINTER (format_type_id);
|
||||
const char *p = IDENTIFIER_POINTER (format_type_id);
|
||||
|
||||
if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
|
||||
{
|
||||
@ -713,7 +760,7 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("`%s' is an unrecognized format function type", p);
|
||||
warning ("`%s' is an unrecognized format function type", p);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -880,6 +927,40 @@ decl_attributes (node, attributes, prefix_attributes)
|
||||
else
|
||||
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
|
||||
break;
|
||||
|
||||
case A_NO_CHECK_MEMORY_USAGE:
|
||||
if (TREE_CODE (decl) != FUNCTION_DECL)
|
||||
{
|
||||
error_with_decl (decl,
|
||||
"`%s' attribute applies only to functions",
|
||||
IDENTIFIER_POINTER (name));
|
||||
}
|
||||
else if (DECL_INITIAL (decl))
|
||||
{
|
||||
error_with_decl (decl,
|
||||
"can't set `%s' attribute after definition",
|
||||
IDENTIFIER_POINTER (name));
|
||||
}
|
||||
else
|
||||
DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
|
||||
break;
|
||||
|
||||
case A_NO_INSTRUMENT_FUNCTION:
|
||||
if (TREE_CODE (decl) != FUNCTION_DECL)
|
||||
{
|
||||
error_with_decl (decl,
|
||||
"`%s' attribute applies only to functions",
|
||||
IDENTIFIER_POINTER (name));
|
||||
}
|
||||
else if (DECL_INITIAL (decl))
|
||||
{
|
||||
error_with_decl (decl,
|
||||
"can't set `%s' attribute after definition",
|
||||
IDENTIFIER_POINTER (name));
|
||||
}
|
||||
else
|
||||
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -999,7 +1080,7 @@ strip_attrs (specs_attrs)
|
||||
#define T_ST &sizetype
|
||||
|
||||
typedef struct {
|
||||
char *format_chars;
|
||||
const char *format_chars;
|
||||
int pointer_count;
|
||||
/* Type of argument if no length modifier is used. */
|
||||
tree *nolen;
|
||||
@ -1022,7 +1103,7 @@ typedef struct {
|
||||
If NULL, then this modifier is not allowed. */
|
||||
tree *zlen;
|
||||
/* List of other modifier characters allowed with these options. */
|
||||
char *flag_chars;
|
||||
const char *flag_chars;
|
||||
} format_char_info;
|
||||
|
||||
static format_char_info print_char_table[] = {
|
||||
@ -1043,7 +1124,7 @@ static format_char_info print_char_table[] = {
|
||||
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
|
||||
{ "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
|
||||
{ "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, NULL, "" },
|
||||
{ NULL }
|
||||
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static format_char_info scan_char_table[] = {
|
||||
@ -1057,7 +1138,7 @@ static format_char_info scan_char_table[] = {
|
||||
{ "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
|
||||
{ "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
|
||||
{ "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, NULL, "" },
|
||||
{ NULL }
|
||||
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Handle format characters recognized by glibc's strftime.c.
|
||||
@ -1082,7 +1163,7 @@ static format_char_info time_char_table[] = {
|
||||
{ "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" },
|
||||
{ "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" },
|
||||
{ "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" },
|
||||
{ NULL }
|
||||
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
typedef struct function_format_info
|
||||
@ -1230,7 +1311,11 @@ record_international_format (name, assembler_name, format_num)
|
||||
info->format_num = format_num;
|
||||
}
|
||||
|
||||
static char tfaff[] = "too few arguments for format";
|
||||
static void
|
||||
tfaff ()
|
||||
{
|
||||
warning ("too few arguments for format");
|
||||
}
|
||||
|
||||
/* Check the argument list of a call to printf, scanf, etc.
|
||||
NAME is the function identifier.
|
||||
@ -1280,7 +1365,7 @@ check_format_info (info, params)
|
||||
tree cur_type;
|
||||
tree wanted_type;
|
||||
tree first_fillin_param;
|
||||
char *format_chars;
|
||||
const char *format_chars;
|
||||
format_char_info *fci = NULL;
|
||||
char flag_chars[8];
|
||||
int has_operand_number = 0;
|
||||
@ -1445,7 +1530,7 @@ check_format_info (info, params)
|
||||
it is an operand number, so set PARAMS to that operand. */
|
||||
if (*format_chars >= '0' && *format_chars <= '9')
|
||||
{
|
||||
char *p = format_chars;
|
||||
const char *p = format_chars;
|
||||
|
||||
while (*p >= '0' && *p++ <= '9')
|
||||
;
|
||||
@ -1498,7 +1583,7 @@ check_format_info (info, params)
|
||||
++format_chars;
|
||||
if (params == 0)
|
||||
{
|
||||
warning (tfaff);
|
||||
tfaff ();
|
||||
return;
|
||||
}
|
||||
if (info->first_arg_num != 0)
|
||||
@ -1542,7 +1627,7 @@ check_format_info (info, params)
|
||||
++format_chars;
|
||||
if (params == 0)
|
||||
{
|
||||
warning (tfaff);
|
||||
tfaff ();
|
||||
return;
|
||||
}
|
||||
cur_param = TREE_VALUE (params);
|
||||
@ -1761,7 +1846,7 @@ check_format_info (info, params)
|
||||
if (precise && index (flag_chars, '0') != 0
|
||||
&& (format_char == 'd' || format_char == 'i'
|
||||
|| format_char == 'o' || format_char == 'u'
|
||||
|| format_char == 'x' || format_char == 'x'))
|
||||
|| format_char == 'x' || format_char == 'X'))
|
||||
warning ("`0' flag ignored with precision specifier and `%c' format",
|
||||
format_char);
|
||||
switch (length_char)
|
||||
@ -1786,7 +1871,7 @@ check_format_info (info, params)
|
||||
continue;
|
||||
if (params == 0)
|
||||
{
|
||||
warning (tfaff);
|
||||
tfaff ();
|
||||
return;
|
||||
}
|
||||
cur_param = TREE_VALUE (params);
|
||||
@ -1812,9 +1897,9 @@ check_format_info (info, params)
|
||||
continue;
|
||||
}
|
||||
if (TREE_CODE (cur_type) != ERROR_MARK)
|
||||
warning ("format argument is not a %s (arg %d)",
|
||||
((fci->pointer_count + aflag == 1)
|
||||
? "pointer" : "pointer to a pointer"),
|
||||
warning ((fci->pointer_count + aflag == 1
|
||||
? "format argument is not a pointer (arg %d)"
|
||||
: "format argument is not a pointer to a pointer (arg %d)"),
|
||||
arg_num);
|
||||
break;
|
||||
}
|
||||
@ -1854,8 +1939,8 @@ check_format_info (info, params)
|
||||
&& (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node
|
||||
|| TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node)))
|
||||
{
|
||||
register char *this;
|
||||
register char *that;
|
||||
register const char *this;
|
||||
register const char *that;
|
||||
|
||||
this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
|
||||
that = 0;
|
||||
@ -2124,8 +2209,10 @@ type_for_mode (mode, unsignedp)
|
||||
if (mode == TYPE_MODE (intDI_type_node))
|
||||
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
|
||||
|
||||
#if HOST_BITS_PER_WIDE_INT >= 64
|
||||
if (mode == TYPE_MODE (intTI_type_node))
|
||||
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
|
||||
#endif
|
||||
|
||||
if (mode == TYPE_MODE (float_type_node))
|
||||
return float_type_node;
|
||||
@ -2183,7 +2270,7 @@ void
|
||||
binary_op_error (code)
|
||||
enum tree_code code;
|
||||
{
|
||||
register char *opname;
|
||||
register const char *opname;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
@ -2474,18 +2561,18 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
|
||||
/* This is the case of (char)x >?< 0x80, which people used to use
|
||||
expecting old C compilers to change the 0x80 into -0x80. */
|
||||
if (val == boolean_false_node)
|
||||
warning ("comparison is always 0 due to limited range of data type");
|
||||
warning ("comparison is always false due to limited range of data type");
|
||||
if (val == boolean_true_node)
|
||||
warning ("comparison is always 1 due to limited range of data type");
|
||||
warning ("comparison is always true due to limited range of data type");
|
||||
}
|
||||
|
||||
if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
|
||||
{
|
||||
/* This is the case of (unsigned char)x >?< -1 or < 0. */
|
||||
if (val == boolean_false_node)
|
||||
warning ("comparison is always 0 due to limited range of data type");
|
||||
warning ("comparison is always false due to limited range of data type");
|
||||
if (val == boolean_true_node)
|
||||
warning ("comparison is always 1 due to limited range of data type");
|
||||
warning ("comparison is always true due to limited range of data type");
|
||||
}
|
||||
|
||||
if (val != 0)
|
||||
@ -2551,7 +2638,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
|
||||
&& ! (TREE_CODE (primop0) == INTEGER_CST
|
||||
&& ! TREE_OVERFLOW (convert (signed_type (type),
|
||||
primop0))))
|
||||
warning ("unsigned value >= 0 is always 1");
|
||||
warning ("comparison of unsigned expression >= 0 is always true");
|
||||
value = boolean_true_node;
|
||||
break;
|
||||
|
||||
@ -2560,7 +2647,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
|
||||
&& ! (TREE_CODE (primop0) == INTEGER_CST
|
||||
&& ! TREE_OVERFLOW (convert (signed_type (type),
|
||||
primop0))))
|
||||
warning ("unsigned value < 0 is always 0");
|
||||
warning ("comparison of unsigned expression < 0 is always false");
|
||||
value = boolean_false_node;
|
||||
break;
|
||||
|
||||
@ -2785,7 +2872,7 @@ truthvalue_conversion (expr)
|
||||
unsigned char *yy_cur, *yy_lim;
|
||||
|
||||
#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
|
||||
#define UNGETC(c) ((c), yy_cur--)
|
||||
#define UNGETC(c) ((c) == EOF ? 0 : yy_cur--)
|
||||
|
||||
int
|
||||
yy_get_token ()
|
||||
@ -2959,15 +3046,134 @@ get_directive_line (finput)
|
||||
down to the element type of an array. */
|
||||
|
||||
tree
|
||||
c_build_type_variant (type, constp, volatilep)
|
||||
c_build_qualified_type (type, type_quals)
|
||||
tree type;
|
||||
int constp, volatilep;
|
||||
int type_quals;
|
||||
{
|
||||
/* A restrict-qualified pointer type must be a pointer to object or
|
||||
incomplete type. Note that the use of POINTER_TYPE_P also allows
|
||||
REFERENCE_TYPEs, which is appropriate for C++. Unfortunately,
|
||||
the C++ front-end also use POINTER_TYPE for pointer-to-member
|
||||
values, so even though it should be illegal to use `restrict'
|
||||
with such an entity we don't flag that here. Thus, special case
|
||||
code for that case is required in the C++ front-end. */
|
||||
if ((type_quals & TYPE_QUAL_RESTRICT)
|
||||
&& (!POINTER_TYPE_P (type)
|
||||
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (type))))
|
||||
{
|
||||
error ("invalid use of `restrict'");
|
||||
type_quals &= ~TYPE_QUAL_RESTRICT;
|
||||
}
|
||||
|
||||
if (TREE_CODE (type) == ARRAY_TYPE)
|
||||
return build_array_type (c_build_type_variant (TREE_TYPE (type),
|
||||
constp, volatilep),
|
||||
return build_array_type (c_build_qualified_type (TREE_TYPE (type),
|
||||
type_quals),
|
||||
TYPE_DOMAIN (type));
|
||||
return build_type_variant (type, constp, volatilep);
|
||||
return build_qualified_type (type, type_quals);
|
||||
}
|
||||
|
||||
/* Apply the TYPE_QUALS to the new DECL. */
|
||||
|
||||
void
|
||||
c_apply_type_quals_to_decl (type_quals, decl)
|
||||
int type_quals;
|
||||
tree decl;
|
||||
{
|
||||
if (type_quals & TYPE_QUAL_CONST)
|
||||
TREE_READONLY (decl) = 1;
|
||||
if (type_quals & TYPE_QUAL_VOLATILE)
|
||||
{
|
||||
TREE_SIDE_EFFECTS (decl) = 1;
|
||||
TREE_THIS_VOLATILE (decl) = 1;
|
||||
}
|
||||
if (type_quals & TYPE_QUAL_RESTRICT)
|
||||
{
|
||||
if (!TREE_TYPE (decl)
|
||||
|| !POINTER_TYPE_P (TREE_TYPE (decl))
|
||||
|| !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (TREE_TYPE (decl))))
|
||||
error ("invalid use of `restrict'");
|
||||
else if (flag_strict_aliasing)
|
||||
{
|
||||
/* No two restricted pointers can point at the same thing.
|
||||
However, a restricted pointer can point at the same thing
|
||||
as an unrestricted pointer, if that unrestricted pointer
|
||||
is based on the restricted pointer. So, we make the
|
||||
alias set for the restricted pointer a subset of the
|
||||
alias set for the type pointed to by the type of the
|
||||
decl. */
|
||||
|
||||
int pointed_to_alias_set
|
||||
= get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
|
||||
|
||||
if (!pointed_to_alias_set)
|
||||
/* It's not legal to make a subset of alias set zero. */
|
||||
;
|
||||
else
|
||||
{
|
||||
DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
|
||||
record_alias_subset (pointed_to_alias_set,
|
||||
DECL_POINTER_ALIAS_SET (decl));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* T is an expression with pointer type. Find the DECL on which this
|
||||
expression is based. (For example, in `a[i]' this would be `a'.)
|
||||
If there is no such DECL, or a unique decl cannot be determined,
|
||||
NULL_TREE is retured. */
|
||||
|
||||
static tree
|
||||
c_find_base_decl (t)
|
||||
tree t;
|
||||
{
|
||||
int i;
|
||||
tree decl;
|
||||
|
||||
if (t == NULL_TREE || t == error_mark_node)
|
||||
return NULL_TREE;
|
||||
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (t)))
|
||||
return NULL_TREE;
|
||||
|
||||
decl = NULL_TREE;
|
||||
|
||||
if (TREE_CODE (t) == FIELD_DECL
|
||||
|| TREE_CODE (t) == PARM_DECL
|
||||
|| TREE_CODE (t) == VAR_DECL)
|
||||
/* Aha, we found a pointer-typed declaration. */
|
||||
return t;
|
||||
|
||||
/* It would be nice to deal with COMPONENT_REFs here. If we could
|
||||
tell that `a' and `b' were the same, then `a->f' and `b->f' are
|
||||
also the same. */
|
||||
|
||||
/* Handle general expressions. */
|
||||
switch (TREE_CODE_CLASS (TREE_CODE (t)))
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
for (i = tree_code_length [(int) TREE_CODE (t)]; --i >= 0;)
|
||||
{
|
||||
tree d = c_find_base_decl (TREE_OPERAND (t, i));
|
||||
if (d)
|
||||
{
|
||||
if (!decl)
|
||||
decl = d;
|
||||
else if (d && d != decl)
|
||||
/* Two different declarations. That's confusing; let's
|
||||
just assume we don't know what's going on. */
|
||||
decl = NULL_TREE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
/* Return the typed-based alias set for T, which may be an expression
|
||||
@ -2977,21 +3183,20 @@ int
|
||||
c_get_alias_set (t)
|
||||
tree t;
|
||||
{
|
||||
static int next_set = 0;
|
||||
tree type;
|
||||
tree u;
|
||||
|
||||
if (t == error_mark_node)
|
||||
return 0;
|
||||
|
||||
type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
|
||||
? t : TREE_TYPE (t);
|
||||
? t : TREE_TYPE (t);
|
||||
|
||||
if (type == error_mark_node)
|
||||
return 0;
|
||||
|
||||
if (TYPE_ALIAS_SET_KNOWN_P (type))
|
||||
/* If we've already calculated the value, just return it. */
|
||||
return TYPE_ALIAS_SET (type);
|
||||
/* Deal with special cases first; for certain kinds of references
|
||||
we're interested in more than just the type. */
|
||||
|
||||
if (TREE_CODE (t) == BIT_FIELD_REF)
|
||||
/* Perhaps reads and writes to this piece of data alias fields
|
||||
@ -2999,22 +3204,48 @@ c_get_alias_set (t)
|
||||
let's just assume that bitfields can alias everything, which is
|
||||
the conservative assumption. */
|
||||
return 0;
|
||||
if (TREE_CODE (t) == COMPONENT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE)
|
||||
/* Permit type-punning when accessing a union, provided the
|
||||
access is directly through the union. For example, this code does
|
||||
not permit taking the address of a union member and then
|
||||
storing through it. Even the type-punning allowed here is a
|
||||
GCC extension, albeit a common and useful one; the C standard
|
||||
says that such accesses have implementation-defined behavior. */
|
||||
return 0;
|
||||
else if (TYPE_MAIN_VARIANT (type) != type)
|
||||
|
||||
/* Permit type-punning when accessing a union, provided the access
|
||||
is directly through the union. For example, this code does not
|
||||
permit taking the address of a union member and then storing
|
||||
through it. Even the type-punning allowed here is a GCC
|
||||
extension, albeit a common and useful one; the C standard says
|
||||
that such accesses have implementation-defined behavior. */
|
||||
for (u = t;
|
||||
TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
|
||||
u = TREE_OPERAND (u, 0))
|
||||
if (TREE_CODE (u) == COMPONENT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
|
||||
return 0;
|
||||
|
||||
if (TREE_CODE (t) == INDIRECT_REF)
|
||||
{
|
||||
/* The C standard specifically allows aliasing between
|
||||
cv-qualified variants of types. */
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
|
||||
return TYPE_ALIAS_SET (type);
|
||||
/* Check for accesses through restrict-qualified pointers. */
|
||||
tree decl = c_find_base_decl (TREE_OPERAND (t, 0));
|
||||
|
||||
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
|
||||
/* We use the alias set indicated in the declaration. */
|
||||
return DECL_POINTER_ALIAS_SET (decl);
|
||||
}
|
||||
|
||||
/* From here on, only the type matters. */
|
||||
|
||||
if (TREE_CODE (t) == COMPONENT_REF
|
||||
&& DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1)))
|
||||
/* Since build_modify_expr calls get_unwidened for stores to
|
||||
component references, the type of a bit field can be changed
|
||||
from (say) `unsigned int : 16' to `unsigned short' or from
|
||||
`enum E : 16' to `short'. We want the real type of the
|
||||
bit-field in this case, not some the integral equivalent. */
|
||||
type = DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1));
|
||||
|
||||
if (TYPE_ALIAS_SET_KNOWN_P (type))
|
||||
/* If we've already calculated the value, just return it. */
|
||||
return TYPE_ALIAS_SET (type);
|
||||
else if (TYPE_MAIN_VARIANT (type) != type)
|
||||
/* The C standard specifically allows aliasing between
|
||||
cv-qualified variants of types. */
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
|
||||
else if (TREE_CODE (type) == INTEGER_TYPE)
|
||||
{
|
||||
tree signed_variant;
|
||||
@ -3025,34 +3256,37 @@ c_get_alias_set (t)
|
||||
signed_variant = signed_type (type);
|
||||
|
||||
if (signed_variant != type)
|
||||
{
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
|
||||
else if (signed_variant == signed_char_type_node)
|
||||
/* The C standard guarantess that any object may be accessed
|
||||
via an lvalue that has character type. We don't have to
|
||||
check for unsigned_char_type_node or char_type_node because
|
||||
we are specifically looking at the signed variant. */
|
||||
{
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
}
|
||||
else if (TREE_CODE (type) == ARRAY_TYPE)
|
||||
/* Anything that can alias one of the array elements can alias
|
||||
the entire array as well. */
|
||||
TYPE_ALIAS_SET (type) = c_get_alias_set (TREE_TYPE (type));
|
||||
else if (TREE_CODE (type) == FUNCTION_TYPE)
|
||||
/* There are no objects of FUNCTION_TYPE, so there's no point in
|
||||
using up an alias set for them. (There are, of course,
|
||||
pointers and references to functions, but that's
|
||||
different.) */
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
else if (TREE_CODE (type) == RECORD_TYPE
|
||||
|| TREE_CODE (type) == UNION_TYPE)
|
||||
{
|
||||
/* If TYPE is a struct or union type then we're reading or
|
||||
writing an entire struct. Thus, we don't know anything about
|
||||
aliasing. (In theory, such an access can only alias objects
|
||||
whose type is the same as one of the fields, recursively, but
|
||||
we don't yet make any use of that information.) */
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
/* If TYPE is a struct or union type then we're reading or
|
||||
writing an entire struct. Thus, we don't know anything about
|
||||
aliasing. (In theory, such an access can only alias objects
|
||||
whose type is the same as one of the fields, recursively, but
|
||||
we don't yet make any use of that information.) */
|
||||
TYPE_ALIAS_SET (type) = 0;
|
||||
|
||||
if (!TYPE_ALIAS_SET_KNOWN_P (type))
|
||||
/* TYPE is something we haven't seen before. Put it in a new
|
||||
alias set. */
|
||||
TYPE_ALIAS_SET (type) = new_alias_set ();
|
||||
|
||||
/* TYPE is something we haven't seen before. Put it in a new alias
|
||||
set. */
|
||||
TYPE_ALIAS_SET (type) = ++next_set;
|
||||
return TYPE_ALIAS_SET (type);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user