summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/c-common.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-10-16 08:28:26 +0000
committerobrien <obrien@FreeBSD.org>1999-10-16 08:28:26 +0000
commitc88c634d26296b35b2f3019e82f9a62664cb56a9 (patch)
tree126c87ca7822c69f7f4d834191547611a2347ed4 /contrib/gcc/c-common.c
parentb86ce00be8423ca89c5df153b1e2878d41de5dd9 (diff)
downloadFreeBSD-src-c88c634d26296b35b2f3019e82f9a62664cb56a9.zip
FreeBSD-src-c88c634d26296b35b2f3019e82f9a62664cb56a9.tar.gz
Merge our -fformat-extensions and printf0() into GCC 2.95.1.
Diffstat (limited to 'contrib/gcc/c-common.c')
-rw-r--r--contrib/gcc/c-common.c410
1 files changed, 322 insertions, 88 deletions
diff --git a/contrib/gcc/c-common.c b/contrib/gcc/c-common.c
index 53a8bba..789b7eb 100644
--- a/contrib/gcc/c-common.c
+++ b/contrib/gcc/c-common.c
@@ -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);
}
OpenPOWER on IntegriCloud