diff options
author | obrien <obrien@FreeBSD.org> | 1999-10-16 08:28:26 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1999-10-16 08:28:26 +0000 |
commit | c88c634d26296b35b2f3019e82f9a62664cb56a9 (patch) | |
tree | 126c87ca7822c69f7f4d834191547611a2347ed4 | |
parent | b86ce00be8423ca89c5df153b1e2878d41de5dd9 (diff) | |
download | FreeBSD-src-c88c634d26296b35b2f3019e82f9a62664cb56a9.zip FreeBSD-src-c88c634d26296b35b2f3019e82f9a62664cb56a9.tar.gz |
Merge our -fformat-extensions and printf0() into GCC 2.95.1.
-rw-r--r-- | contrib/gcc/c-common.c | 410 |
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); } |