Merge our -fformat-extensions and printf0() into GCC 2.95.1.

This commit is contained in:
obrien 1999-10-16 08:28:26 +00:00
parent fa8af026d5
commit 1850ef0c96

View File

@ -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);
}