From 097c4e0439278c4083db561991d7649b4e51f88a Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Thu, 26 Jun 2003 18:30:06 +0000 Subject: Introduce a simple static checker for making sure that the bounds length passed to common functions such as strlcpy/strlcat match the real length of the buffer. It also checks to make sure that the bound length was not incorrectly derived from a sizeof(pointer) operation. Functions must be marked with the new attribute __bounded__, and warnings are turned on by -Wbounded. Specifying -Wformat also enables bounds checking for scanf(3) bounds to '%s' format variables. -Wall now turns on -Wbounded also. The checking is pretty limited right now to constant parameters, and the buffers must be statically declared, and not inside a record type. This simple checking still found hundreds of bugs around the ports tree though, and there have been no false positive warnings. 10x to niklas@, Richard Sharp and David Scott {rich,dave}@recoil.org for compiler advice. deraadt@ ok, miod@ tested on his collection of hardware You need to recompile gcc now if source upgrading in -current before doing a make world. --- gnu/egcs/gcc/c-common.c | 422 +++++++++++++++++++++++++++++++++++++++++++++- gnu/egcs/gcc/c-decl.c | 9 + gnu/egcs/gcc/c-tree.h | 5 + gnu/egcs/gcc/c-typeck.c | 20 ++- gnu/egcs/gcc/cp/call.c | 142 ++++++++++------ gnu/egcs/gcc/cp/cp-tree.h | 96 +++++++++-- gnu/egcs/gcc/cp/decl2.c | 249 ++++++++++++++++++++++----- gnu/egcs/gcc/cp/typeck.c | 148 ++++++++++------ gnu/egcs/gcc/fold-const.c | 82 ++++++--- gnu/egcs/gcc/toplev.c | 2 + gnu/egcs/gcc/tree.h | 18 +- 11 files changed, 1018 insertions(+), 175 deletions(-) (limited to 'gnu') diff --git a/gnu/egcs/gcc/c-common.c b/gnu/egcs/gcc/c-common.c index 38bf4927916..167781113bc 100644 --- a/gnu/egcs/gcc/c-common.c +++ b/gnu/egcs/gcc/c-common.c @@ -57,11 +57,14 @@ 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, A_NONNULL, - A_SENTINEL }; + A_SENTINEL, A_BOUNDED}; enum format_type { printf_format_type, scanf_format_type, strftime_format_type, syslog_format_type }; +enum bounded_type { buffer_bound_type, string_bound_type, + minbytes_bound_type, size_bound_type }; + static void declare_hidden_char_array PROTO((const char *, const char *)); static void add_attribute PROTO((enum attrs, const char *, int, int, int)); @@ -393,6 +396,7 @@ init_attributes () add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1); add_attribute (A_NONNULL, "nonnull", 0, -1, 1); add_attribute (A_SENTINEL, "sentinel", 0, 0, 1); + add_attribute (A_BOUNDED, "bounded", 3, 4, 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); @@ -438,6 +442,8 @@ static function_attribute_info *new_function_format static function_attribute_info *new_international_format PROTO((int)); static function_attribute_info *new_nonnull_info PROTO((int)); static function_attribute_info *new_sentinel_info PROTO((int)); +static function_attribute_info *new_bound_check_info + PROTO((enum bounded_type, int, int, int)); static function_attributes_info *insert_function_attribute PROTO((function_attributes_info *, tree, tree, function_attribute_info *)); @@ -849,6 +855,183 @@ decl_attributes (node, attributes, prefix_attributes) break; } + case A_BOUNDED: + { + tree bounded_type_id = TREE_VALUE (args); + tree bounded_buf_expr = TREE_VALUE (TREE_CHAIN (args)); + tree bounded_num_expr = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + tree bounded_size_expr = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (args))); + int bounded_num, bounded_buf, bounded_size, arg_num; + enum bounded_type bounded_type = string_bound_type; + tree argument, arg_iterate; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "attribute bounded specified for non-function `%s'"); + continue; + } + + if (TREE_CODE (bounded_type_id) != IDENTIFIER_NODE) + { + error ("unrecognized bounded type specifier"); + continue; + } + else + { + const char *p = IDENTIFIER_POINTER (bounded_type_id); + + if (!strcmp (p, "string") || !strcmp (p, "__string__")) + bounded_type = string_bound_type; + else if (!strcmp (p, "buffer") || !strcmp (p, "__buffer__")) + bounded_type = buffer_bound_type; + else if (!strcmp (p, "minbytes") || !strcmp (p, "__minbytes__")) + bounded_type = minbytes_bound_type; + else if (!strcmp (p, "size") || !strcmp (p, "__size__")) + bounded_type = size_bound_type; + else + { + warning ("`%s' is an unrecognized bounded function type", p); + continue; + } + } + + /* Extract the third argument if its appropriate */ + switch (bounded_type) + { + case string_bound_type: + if (bounded_size_expr) + warning ("`string' bound type only takes 2 parameters"); + bounded_size_expr = size_int (0); + break; + case buffer_bound_type: + if (bounded_size_expr) + warning ("`buffer' bound type only takes 2 parameters"); + bounded_size_expr = size_int (0); + break; + case minbytes_bound_type: + if (bounded_size_expr) + warning("`minbytes' bound type only takes 2 parameters"); + bounded_size_expr = size_int (0); + break; + case size_bound_type: + if (bounded_size_expr) + bounded_size_expr = TREE_VALUE (bounded_size_expr); + else + { + error ("parameter 3 not specified for `size' bounded function"); + continue; + } + break; + } + + /* Strip any conversions from the buffer parameters and verify they + are constants */ + while (TREE_CODE (bounded_num_expr) == NOP_EXPR + || TREE_CODE (bounded_num_expr) == CONVERT_EXPR + || TREE_CODE (bounded_num_expr) == NON_LVALUE_EXPR) + bounded_num_expr = TREE_OPERAND (bounded_num_expr, 0); + + while (TREE_CODE (bounded_buf_expr) == NOP_EXPR + || TREE_CODE (bounded_buf_expr) == CONVERT_EXPR + || TREE_CODE (bounded_buf_expr) == NON_LVALUE_EXPR) + bounded_buf_expr = TREE_OPERAND (bounded_buf_expr, 0); + + while (TREE_CODE (bounded_size_expr) == NOP_EXPR + || TREE_CODE (bounded_size_expr) == CONVERT_EXPR + || TREE_CODE (bounded_size_expr) == NON_LVALUE_EXPR) + bounded_size_expr = TREE_OPERAND (bounded_size_expr, 0); + + if (TREE_CODE (bounded_num_expr) != INTEGER_CST) + { + error ("bound length operand number is not an integer constant"); + continue; + } + + if (TREE_CODE (bounded_buf_expr) != INTEGER_CST) + { + error ("bound buffer operand number is not an integer constant"); + continue; + } + + if (TREE_CODE (bounded_size_expr) != INTEGER_CST) + { + error ("bound element size operand number is not an integer constant"); + continue; + } + + bounded_num = TREE_INT_CST_LOW (bounded_num_expr); + bounded_buf = TREE_INT_CST_LOW (bounded_buf_expr); + bounded_size = TREE_INT_CST_LOW (bounded_size_expr); + argument = TYPE_ARG_TYPES (type); + + /* `min_size' directly specifies the minimum buffer length */ + if (bounded_type == minbytes_bound_type && bounded_num <= 0) + { + error ("`minbytes' bound size must be a positive integer value"); + continue; + } + + /* Check the function arguments for correct types */ + if (argument) + { + arg_iterate = argument; + for (arg_num = 1; ; ++arg_num) + { + if (arg_iterate == 0 || arg_num == bounded_buf) + break; + arg_iterate = TREE_CHAIN (arg_iterate); + } + if (! arg_iterate + || (TREE_CODE (TREE_VALUE (arg_iterate)) != POINTER_TYPE + && TREE_CODE (TREE_VALUE (arg_iterate)) != ARRAY_TYPE)) + { + error ("bound buffer argument not an array or pointer type"); + continue; + } + + if (bounded_type == size_bound_type + || bounded_type == string_bound_type + || bounded_type == buffer_bound_type) + { + arg_iterate = argument; + for (arg_num = 1; ; ++arg_num) + { + if (arg_iterate == 0 || arg_num == bounded_num) + break; + arg_iterate = TREE_CHAIN (arg_iterate); + } + if (! arg_iterate + || TREE_CODE (TREE_VALUE (arg_iterate)) != INTEGER_TYPE) + { + error ("bound length argument not an integer type"); + continue; + } + } + + if (bounded_type == size_bound_type) + { + arg_iterate = argument; + for (arg_num = 1; ; ++arg_num) + { + if (arg_iterate == 0 || arg_num == bounded_size) + break; + arg_iterate = TREE_CHAIN (arg_iterate); + } + if (! arg_iterate + || TREE_CODE (TREE_VALUE (arg_iterate)) != INTEGER_TYPE) + { + error ("bound element size argument not an integer type"); + continue; + } + } + } + + list = insert_function_attribute (list, DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + new_bound_check_info (bounded_type, bounded_buf, bounded_num, bounded_size)); + break; + } case A_FORMAT_ARG: { tree format_num_expr = TREE_VALUE (args); @@ -1331,12 +1514,23 @@ typedef struct sentinel_info int argument_num; /* number of non-null argument */ } sentinel_info; +typedef struct bound_check_info +{ + struct function_attribute_info *next; + enum attrs type; + enum bounded_type bounded_type; /* type of bound (string, minsize, etc) */ + int argument_buf; /* number of buffer pointer arg */ + int argument_num; /* number of buffer length arg || min size */ + int argument_size; /* number of buffer element size arg */ +} bound_check_info; + static function_attribute_info *find_function_attribute PROTO((tree, tree, enum attrs)); static void check_format_info PROTO((function_format_info *, tree)); static void check_nonnull_info PROTO((nonnull_info *, tree)); static void check_sentinel_info PROTO((sentinel_info *, tree)); +static void check_bound_info PROTO((bound_check_info *, tree)); /* Helper function for setting up initial attribute for printf-like functions, since the format argument is also non-null checked for @@ -1467,6 +1661,27 @@ new_sentinel_info (argument_num) return (function_attribute_info *) (info); } +/* Create information record for functions with bounded parameters + ARGUMENT_BUF is the number of the buffer pointer argument. + ARGUMENT_NUM is the number of the buffer length argument. */ + +static function_attribute_info * +new_bound_check_info (argument_type, argument_buf, argument_num, argument_size) + enum bounded_type argument_type; + int argument_buf, argument_num, argument_size; +{ + bound_check_info *info; + info = (bound_check_info *) + xmalloc (sizeof (bound_check_info)); + info->next = NULL; + info->type = A_BOUNDED; + info->bounded_type = argument_type; + info->argument_buf = argument_buf; + info->argument_num = argument_num; + info->argument_size = argument_size; + return (function_attribute_info *) (info); +} + /* Record attribute information for the names of function. Used as: * newlist = insert_function_attribute (old, name, asm, new_xxx (...) ); * In reality, newlist == old if old != NULL, but clients don't need to @@ -1568,6 +1783,39 @@ check_function_format (name, assembler_name, params) } } +/* Check the argument list of a call to strlcpy, strcat, etc. + NAME is the function identifier. + ASSEMBLER_NAME is the function's assembler identifier. + (Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.) + PARAMS is the list of argument values. */ + +void +check_function_bounds (name, assembler_name, params) + tree name; + tree assembler_name; + tree params; +{ + function_attributes_info *info; + function_attribute_info *ck; + + /* See if this function has attributes. */ + for (info = function_attributes_list; info; info = info->next) + { + if (info->assembler_name + ? (info->assembler_name == assembler_name) + : (info->name == name)) + { + /* Yup; check those attributes. */ + for (ck = info->first; ck; ck = ck->next) + { + if (ck->type == A_BOUNDED) + check_bound_info ((bound_check_info *)ck, params); + } + break; + } + } +} + /* Find a function attribute corresponding to given function names, and a given attribute TYPE. */ @@ -1677,6 +1925,144 @@ check_nonnull_info (info, params) } } +/* Given two arguments (a buffer and buffer length), check + that the buffer length was not derived from the size of + a pointer, and that the length arg is not greater than + the static buffer size. */ + +static void +check_bound_info (info, params) + bound_check_info *info; + tree params; +{ + tree buf_expr, length_expr, record_expr, size_expr; + int arg_num; + + /* Extract the buffer expression from the arguments */ + buf_expr = params; + for (arg_num = 1; ; ++arg_num) + { + if (buf_expr == 0) + return; + if (arg_num == info->argument_buf) + break; + buf_expr = TREE_CHAIN (buf_expr); + } + buf_expr = TREE_VALUE (buf_expr); + + /* Get the buffer length, either directly from the function attribute + info, or from the parameter pointed to */ + if (info->bounded_type == minbytes_bound_type) + length_expr = size_int (info->argument_num); + else + { + /* Extract the buffer length expression from the arguments */ + length_expr = params; + for (arg_num = 1; ; ++arg_num) + { + if (length_expr == 0) + return; + if (arg_num == info->argument_num) + break; + length_expr = TREE_CHAIN (length_expr); + } + length_expr = TREE_VALUE (length_expr); + } + + /* If the bound type is `size', resolve the third parameter */ + if (info->bounded_type == size_bound_type) + { + size_expr = params; + for (arg_num = 1; ; ++arg_num) + { + if (size_expr == 0) + return; + if (arg_num == info->argument_size) + break; + size_expr = TREE_CHAIN (size_expr); + } + size_expr = TREE_VALUE (size_expr); + } + else + size_expr = size_int (0); + + STRIP_NOPS (buf_expr); + + /* Check for a possible sizeof(pointer) error in string functions */ + if (info->bounded_type == string_bound_type + && SIZEOF_PTR_DERIVED (length_expr)) + warning("sizeof(pointer) possibly incorrect in argument %d", + info->argument_num); + + /* We only need to check if the buffer expression is a static + * array (which is inside an ADDR_EXPR) */ + if (TREE_CODE (buf_expr) != ADDR_EXPR) + return; + buf_expr = TREE_OPERAND (buf_expr, 0); + + if (TREE_CODE (TREE_TYPE (buf_expr)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (buf_expr))) + { + int array_size, length, elem_size, type_size; + tree array_size_expr = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (buf_expr))); + tree array_type = TREE_TYPE (TREE_TYPE (buf_expr)); + + /* Get the size of the type of the array and sanity check it */ + type_size = TREE_INT_CST_LOW (TYPE_SIZE (array_type)); + if ((type_size % 8) != 0) + { + error ("found non-byte aligned type while checking bounds"); + return; + } + type_size /= 8; + + /* Both the size of the static buffer and the length should be + * integer constants by now */ + if (TREE_CODE (array_size_expr) != INTEGER_CST + || TREE_CODE (length_expr) != INTEGER_CST + || TREE_CODE (size_expr) != INTEGER_CST) + return; + + /* array_size_expr contains maximum array index, so add one for size */ + array_size = (TREE_INT_CST_LOW (array_size_expr) + 1) * type_size; + length = TREE_INT_CST_LOW (length_expr); + + /* XXX - warn about a too-small buffer? */ + if (array_size < 1) + return; + + switch (info->bounded_type) + { + case string_bound_type: + case buffer_bound_type: + /* warn about illegal bounds value */ + if (length < 1) + warning ("non-positive bounds length (%d) detected", length); + /* check if the static buffer is smaller than bound length */ + if (array_size < length) + warning("array size (%d) smaller than bound length (%d)", + array_size, length); + break; + case minbytes_bound_type: + /* check if array is smaller than the minimum allowed */ + if (array_size < length) + warning ("array size (%d) is smaller than minimum required (%d)", + array_size, length); + break; + case size_bound_type: + elem_size = TREE_INT_CST_LOW (size_expr); + /* warn about illegal bounds value */ + if (length < 1) + warning ("non-positive bounds length (%d) detected", length); + /* check if the static buffer is smaller than bound length */ + if (array_size < (length * elem_size)) + warning("array size (%d) smaller than required length (%d * %d)", + array_size, length, elem_size); + break; + } + } +} + /* Check the argument list for sentinel values. INFO points to the sentinel_info structure. PARAMS is the list of argument values. */ @@ -1793,6 +2179,7 @@ check_format_info (info, params) while (1) { int aflag; + int format_num = 0; if (*format_chars == 0) { if (format_chars - TREE_STRING_POINTER (format_tree) != format_length) @@ -1817,11 +2204,17 @@ check_format_info (info, params) suppressed = wide = precise = FALSE; if (info->format_type == scanf_format_type) { + char format_num_str[33]; suppressed = *format_chars == '*'; if (suppressed) ++format_chars; - while (ISDIGIT (*format_chars)) + while (ISDIGIT (*format_chars)) { + if (format_num < sizeof(format_num_str)-1) + format_num_str[format_num++] = *format_chars; ++format_chars; + } + format_num_str[format_num] = '\0'; + format_num = atoi(format_num_str); } else if (info->format_type == strftime_format_type) { @@ -2196,6 +2589,31 @@ check_format_info (info, params) break; } + /* Test static string bounds for scanf if -Wbounded is on as well */ + if (warn_bounded + && info->format_type == scanf_format_type + && format_char == 's' + && i == fci->pointer_count + aflag + && cur_param != 0 + && TREE_CODE (cur_type) != ERROR_MARK + && TREE_CODE (TREE_TYPE (cur_param)) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (cur_param))) == INTEGER_TYPE) { + tree array_size_expr = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (cur_param))); + if (array_size_expr != 0) { + int array_size = TREE_INT_CST_LOW (array_size_expr) + 1; + +#if 0 /* Gives false positives at the moment */ + if (format_num == 0) + warning("Unbounded string written into a static array[%d]", + array_size); +#endif + /* Need extra slot for the '\0' */ + if (array_size < (format_num + 1)) + warning("Array size (%d) smaller than format string size (%d)", + array_size, format_num + 1); + } + } + /* See if this is an attempt to write into a const type with scanf or with printf "%n". */ if ((info->format_type == scanf_format_type diff --git a/gnu/egcs/gcc/c-decl.c b/gnu/egcs/gcc/c-decl.c index 1f9aad01ae2..80dd78a6868 100644 --- a/gnu/egcs/gcc/c-decl.c +++ b/gnu/egcs/gcc/c-decl.c @@ -559,6 +559,10 @@ int warn_nested_externs = 0; int warn_format; +/* Warn about potential overruns in static buffers. */ + +int warn_bounded; + /* Warn about a subscript that has type char. */ int warn_char_subscripts = 0; @@ -828,6 +832,10 @@ c_decode_option (argc, argv) warn_format = 1; else if (!strcmp (p, "-Wno-format")) warn_format = 0; + else if (!strcmp (p, "-Wbounded")) + warn_bounded = 1; + else if (!strcmp (p, "-Wno-bounded")) + warn_bounded = 0; else if (!strcmp (p, "-Wchar-subscripts")) warn_char_subscripts = 1; else if (!strcmp (p, "-Wno-char-subscripts")) @@ -899,6 +907,7 @@ c_decode_option (argc, argv) warn_unused = 1; warn_switch = 1; warn_format = 1; + warn_bounded = 1; warn_char_subscripts = 1; warn_parentheses = 1; warn_missing_braces = 1; diff --git a/gnu/egcs/gcc/c-tree.h b/gnu/egcs/gcc/c-tree.h index bcf325b68fd..05943e5d2f0 100644 --- a/gnu/egcs/gcc/c-tree.h +++ b/gnu/egcs/gcc/c-tree.h @@ -180,6 +180,7 @@ extern void declare_function_name PROTO((void)); extern void decl_attributes PROTO((tree, tree, tree)); extern void init_function_format_info PROTO((void)); extern void check_function_format PROTO((tree, tree, tree)); +extern void check_function_bounds PROTO((tree, tree, tree)); extern int c_get_alias_set PROTO((tree)); extern void c_apply_type_quals_to_decl PROTO((int, tree)); /* Print an error message for invalid operands to arith operation CODE. @@ -445,6 +446,10 @@ extern int flag_hosted; extern int warn_implicit; +/* Nonzero means warn about static buffer abuse. */ + +extern int warn_bounded; + /* Nonzero means give string constants the type `const char *' to get extra warnings from them. These warnings will be too numerous to be useful, except in thoroughly ANSIfied programs. */ diff --git a/gnu/egcs/gcc/c-typeck.c b/gnu/egcs/gcc/c-typeck.c index 854baf88823..c1b16f2ca8a 100644 --- a/gnu/egcs/gcc/c-typeck.c +++ b/gnu/egcs/gcc/c-typeck.c @@ -1,5 +1,6 @@ /* Build expressions with type checking for C compiler. - Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -167,7 +168,8 @@ static tree qualify_type (type, like) tree type, like; { - return c_build_qualified_type (type, TYPE_QUALS (like)); + return c_build_qualified_type (type, + TYPE_QUALS (type) | TYPE_QUALS (like)); } /* Return the common type of two types. @@ -838,6 +840,8 @@ c_sizeof (type) t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (TYPE_PRECISION (char_type_node))); t = convert (sizetype, t); + if (code == POINTER_TYPE) + SIZEOF_PTR_DERIVED (t) = 1; /* size_binop does not put the constant in range, so do it now. */ if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0)) TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1; @@ -862,6 +866,8 @@ c_sizeof_nowarn (type) t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (TYPE_PRECISION (char_type_node))); t = convert (sizetype, t); + if (code == POINTER_TYPE) + SIZEOF_PTR_DERIVED (t) = 1; force_fit_type (t, 0); return t; } @@ -1578,6 +1584,9 @@ build_function_call (function, params) if (warn_format && (name || assembler_name)) check_function_format (name, assembler_name, coerced_params); + if (warn_bounded && (name || assembler_name)) + check_function_bounds (name, assembler_name, coerced_params); + /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c to do something useful. */ @@ -5845,7 +5854,7 @@ add_pending_init (purpose, value) p = *q; if (tree_int_cst_lt (purpose, p->purpose)) q = &p->left; - else if (tree_int_cst_lt (p->purpose, purpose)) + else if (p->purpose != purpose) q = &p->right; else abort (); @@ -5859,8 +5868,7 @@ add_pending_init (purpose, value) if (tree_int_cst_lt (DECL_FIELD_BITPOS (purpose), DECL_FIELD_BITPOS (p->purpose))) q = &p->left; - else if (tree_int_cst_lt (DECL_FIELD_BITPOS (p->purpose), - DECL_FIELD_BITPOS (purpose))) + else if (p->purpose != purpose) q = &p->right; else abort (); @@ -6045,7 +6053,7 @@ pending_init_member (field) { while (p) { - if (tree_int_cst_equal (field, p->purpose)) + if (field == p->purpose) return 1; else if (tree_int_cst_lt (field, p->purpose)) p = p->left; diff --git a/gnu/egcs/gcc/cp/call.c b/gnu/egcs/gcc/cp/call.c index 1dccabcf102..b0b73ca2cbb 100644 --- a/gnu/egcs/gcc/cp/call.c +++ b/gnu/egcs/gcc/cp/call.c @@ -599,29 +599,6 @@ build_method_call (instance, name, parms, basetype_path, flags) return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE); } - /* This is the logic that magically deletes the second argument to - operator delete, if it is not needed. */ - if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2) - { - tree save_last = TREE_CHAIN (parms); - - /* get rid of unneeded argument */ - TREE_CHAIN (parms) = NULL_TREE; - if (build_method_call (instance, name, parms, basetype_path, - (LOOKUP_SPECULATIVELY|flags) & ~LOOKUP_COMPLAIN)) - { - /* If it finds a match, return it. */ - return build_method_call (instance, name, parms, basetype_path, flags); - } - /* If it doesn't work, two argument delete must work */ - TREE_CHAIN (parms) = save_last; - } - /* We already know whether it's needed or not for vec delete. */ - else if (name == ansi_opname[(int) VEC_DELETE_EXPR] - && TYPE_LANG_SPECIFIC (TREE_TYPE (instance)) - && ! TYPE_VEC_DELETE_TAKES_SIZE (TREE_TYPE (instance))) - TREE_CHAIN (parms) = NULL_TREE; - if (TREE_CODE (name) == BIT_NOT_EXPR) { if (parms) @@ -1088,8 +1065,8 @@ add_function_candidate (candidates, fn, arglist, flags) tree parmnode, argnode; int viable = 1; - /* The `this' and `in_chrg' arguments to constructors are not considered - in overload resolution. */ + /* The `this', `in_chrg', and `vlist' arguments to constructors are + not considered in overload resolution. */ if (DECL_CONSTRUCTOR_P (fn)) { parmlist = TREE_CHAIN (parmlist); @@ -1099,6 +1076,22 @@ add_function_candidate (candidates, fn, arglist, flags) parmlist = TREE_CHAIN (parmlist); arglist = TREE_CHAIN (arglist); } + if ((flags & LOOKUP_HAS_VLIST) + && DECL_CONSTRUCTOR_FOR_PVBASE_P (fn)) + { + parmlist = TREE_CHAIN (parmlist); + arglist = TREE_CHAIN (arglist); + } + else if (!(flags & LOOKUP_HAS_VLIST) + && !DECL_CONSTRUCTOR_FOR_PVBASE_P (fn)) + /* Ok */; + else + { + /* The ctor expects a vlist and the arguments don't have + one, or vice versa, so fn is not even a candidate, since + the corresponding ctor would be the candidate. */ + return candidates; + } } len = list_length (arglist); @@ -2094,6 +2087,11 @@ build_user_type_conversion_1 (totype, expr, flags) tree t = build_int_2 (0, 0); TREE_TYPE (t) = build_pointer_type (totype); args = build_scratch_list (NULL_TREE, expr); + if (TYPE_USES_PVBASES (totype) && !flag_vtable_thunks_compat) + { + args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args); + flags |= LOOKUP_HAS_VLIST; + } if (TYPE_USES_VIRTUAL_BASECLASSES (totype)) args = scratch_tree_cons (NULL_TREE, integer_one_node, args); args = scratch_tree_cons (NULL_TREE, t, args); @@ -2461,7 +2459,11 @@ build_object_call (obj, args) return error_mark_node; } - if (DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR]) + /* Since cand->fn will be a type, not a function, for a conversion + function, we must be careful not to unconditionally look at + DECL_NAME here. */ + if (TREE_CODE (cand->fn) == FUNCTION_DECL + && DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR]) return build_over_call (cand, mem_args, LOOKUP_NORMAL); obj = convert_like (TREE_VEC_ELT (cand->convs, 0), obj); @@ -2776,9 +2778,19 @@ build_new_op (code, flags, arg1, arg2, arg3) conv = TREE_OPERAND (conv, 0); arg1 = convert_like (conv, arg1); if (arg2) - arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2); + { + conv = TREE_VEC_ELT (cand->convs, 1); + if (TREE_CODE (conv) == REF_BIND) + conv = TREE_OPERAND (conv, 0); + arg2 = convert_like (conv, arg2); + } if (arg3) - arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3); + { + conv = TREE_VEC_ELT (cand->convs, 2); + if (TREE_CODE (conv) == REF_BIND) + conv = TREE_OPERAND (conv, 0); + arg3 = convert_like (conv, arg3); + } builtin: switch (code) @@ -3047,6 +3059,7 @@ convert_like (convs, expr) = WRAPPER_PTR (TREE_OPERAND (convs, 1)); tree fn = cand->fn; tree args; + int flags = LOOKUP_NORMAL; if (DECL_CONSTRUCTOR_P (fn)) { @@ -3054,13 +3067,19 @@ convert_like (convs, expr) TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn)); args = build_scratch_list (NULL_TREE, expr); + if (TYPE_USES_PVBASES (DECL_CONTEXT (fn)) + && !flag_vtable_thunks_compat) + { + args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args); + flags != LOOKUP_HAS_VLIST; + } if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn))) args = scratch_tree_cons (NULL_TREE, integer_one_node, args); args = scratch_tree_cons (NULL_TREE, t, args); } else args = build_this (expr); - expr = build_over_call (cand, args, LOOKUP_NORMAL); + expr = build_over_call (cand, args, flags); /* If this is a constructor or a function returning an aggr type, we need to build up a TARGET_EXPR. */ @@ -3269,6 +3288,13 @@ build_over_call (cand, args, flags) arg = TREE_CHAIN (arg); parm = TREE_CHAIN (parm); } + if (flags & LOOKUP_HAS_VLIST) + { + converted_args = expr_tree_cons + (NULL_TREE, TREE_VALUE (arg), converted_args); + arg = TREE_CHAIN (arg); + parm = TREE_CHAIN (parm); + } } /* Bypass access control for 'this' parameter. */ else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) @@ -3365,6 +3391,10 @@ build_over_call (cand, args, flags) check_function_format (DECL_NAME (fn), DECL_ASSEMBLER_NAME (fn), converted_args); + if (warn_bounded && (DECL_NAME (fn) || DECL_ASSEMBLER_NAME (fn))) + check_function_bounds (DECL_NAME (fn), DECL_ASSEMBLER_NAME (fn), + converted_args); + /* Avoid actually calling copy constructors and copy assignment operators, if possible. */ @@ -3378,6 +3408,8 @@ build_over_call (cand, args, flags) arg = TREE_CHAIN (converted_args); if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn))) arg = TREE_CHAIN (arg); + if (flags & LOOKUP_HAS_VLIST) + arg = TREE_CHAIN (arg); arg = TREE_VALUE (arg); /* Pull out the real argument, disregarding const-correctness. */ @@ -3426,20 +3458,34 @@ build_over_call (cand, args, flags) else if (! real_lvalue_p (arg) || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn))) { + tree address; tree to = stabilize_reference (build_indirect_ref (TREE_VALUE (args), 0)); - /* Don't copy the padding byte; it might not have been allocated - if to is a base subobject. */ - if (is_empty_class (DECL_CLASS_CONTEXT (fn))) - return build_unary_op - (ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to), - cp_convert (void_type_node, arg), to), - 0); - - val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg); + /* If we're initializing an empty class, then we actually + have to use a MODIFY_EXPR rather than an INIT_EXPR. The + reason is that the dummy padding member in the target may + not actually be allocated if TO is a base class + subobject. Since we've set TYPE_NONCOPIED_PARTS on the + padding, a MODIFY_EXPR will preserve its value, which is + the right thing to do if it's not really padding at all. + + It's not safe to just throw away the ARG if we're looking + at an empty class because the ARG might contain a + TARGET_EXPR which wants to be bound to TO. If it is not, + expand_expr will assign a dummy slot for the TARGET_EXPR, + and we will call a destructor for it, which is wrong, + because we will also destroy TO, but will never have + constructed it. */ + val = build (is_empty_class (DECL_CLASS_CONTEXT (fn)) + ? MODIFY_EXPR : INIT_EXPR, + DECL_CONTEXT (fn), to, arg); TREE_SIDE_EFFECTS (val) = 1; - return build_unary_op (ADDR_EXPR, val, 0); + address = build_unary_op (ADDR_EXPR, val, 0); + /* Avoid a warning about this expression, if the address is + never used. */ + TREE_USED (address) = 1; + return address; } } else if (DECL_NAME (fn) == ansi_opname[MODIFY_EXPR] @@ -3451,12 +3497,6 @@ build_over_call (cand, args, flags) arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0); - /* Don't copy the padding byte; it might not have been allocated - if to is a base subobject. */ - if (is_empty_class (DECL_CLASS_CONTEXT (fn))) - return build (COMPOUND_EXPR, TREE_TYPE (to), - cp_convert (void_type_node, arg), to); - val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg); TREE_SIDE_EFFECTS (val) = 1; return val; @@ -3545,6 +3585,8 @@ build_new_method_call (instance, name, args, basetype_path, flags) remove it for error reporting. */ if (flags & LOOKUP_HAS_IN_CHARGE) user_args = TREE_CHAIN (args); + if (flags & LOOKUP_HAS_VLIST) + user_args = TREE_CHAIN (user_args); args = resolve_args (args); @@ -3617,6 +3659,12 @@ build_new_method_call (instance, name, args, basetype_path, flags) if (name == ctor_identifier && TYPE_USES_VIRTUAL_BASECLASSES (basetype) && ! (flags & LOOKUP_HAS_IN_CHARGE)) { + if (TYPE_USES_PVBASES(basetype) + && (!flag_vtable_thunks_compat || (name == dtor_identifier))) + { + args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args); + flags |= LOOKUP_HAS_VLIST; + } flags |= LOOKUP_HAS_IN_CHARGE; args = scratch_tree_cons (NULL_TREE, integer_one_node, args); } @@ -4333,8 +4381,8 @@ joust (cand1, cand2, warn) != DECL_CONSTRUCTOR_P (cand2->fn)) /* Don't warn if the two conv ops convert to the same type... */ || (! DECL_CONSTRUCTOR_P (cand1->fn) - && ! same_type_p (TREE_TYPE (cand1->second_conv), - TREE_TYPE (cand2->second_conv))))) + && ! same_type_p (TREE_TYPE (TREE_TYPE (cand1->fn)), + TREE_TYPE (TREE_TYPE (cand2->fn)))))) { int comp = compare_ics (cand1->second_conv, cand2->second_conv); if (comp != winner) diff --git a/gnu/egcs/gcc/cp/cp-tree.h b/gnu/egcs/gcc/cp/cp-tree.h index 249808974c0..c7c501cbefe 100644 --- a/gnu/egcs/gcc/cp/cp-tree.h +++ b/gnu/egcs/gcc/cp/cp-tree.h @@ -52,8 +52,8 @@ Boston, MA 02111-1307, USA. */ 4: BINFO_NEW_VTABLE_MARKED. TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, or FIELD_DECL). - 5: Not used. - 6: Not used. + 5: TYPE_USES_PVBASES (in a class TYPE). + 6: SIZEOF_PTR_DERIVED (for the bounds checker, string types) Usage of TYPE_LANG_FLAG_?: 0: C_TYPE_FIELDS_READONLY (in RECORD_TYPE or UNION_TYPE). @@ -458,6 +458,10 @@ extern int warn_cast_qual; extern int warn_format; +/* Nonzero means warn about static buffer abuse. */ + +extern int warn_bounded; + /* Nonzero means warn about non virtual destructors in classes that have virtual functions. */ @@ -503,8 +507,9 @@ extern int write_virtuals; /* True for more efficient but incompatible (not fully tested) vtable implementation (using thunks). - 0 is old behavior; 1 is new behavior. */ -extern int flag_vtable_thunks; + 0 is old behavior; 1 is new behavior; 3 adds vlist arguments; + 2 is 3 plus backwards-compatibility to 1. */ +extern int flag_vtable_thunks, flag_vtable_thunks_compat; /* INTERFACE_ONLY nonzero means that we are in an "interface" section of the compiler. INTERFACE_UNKNOWN nonzero means @@ -543,6 +548,10 @@ extern int flag_guiding_decls; and class qualifiers. */ extern int flag_do_squangling; +/* Nonzero means generate separate instantiation control files and juggle + them at link time. */ +extern int flag_use_repository; + /* Nonzero if we want to issue diagnostics that the standard says are not required. */ extern int flag_optional_diags; @@ -885,6 +894,13 @@ struct lang_type hierarchy, then we can use more efficient search techniques. */ #define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3(NODE)) +/* Nonzero means that this _CLASSTYPE uses polymorphic virtual bases. + This flag is set only when we use vtable thunks. */ +#define TYPE_USES_PVBASES(NODE) (TREE_LANG_FLAG_5(NODE)) + +/* Used to track constants derived from sizeof(pointer) operations */ +#define SIZEOF_PTR_DERIVED(NODE) (TREE_LANG_FLAG_6((NODE))) + /* Vector member functions defined in this class. Each element is either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD. All functions with the same name end up in the same slot. The first @@ -961,7 +977,7 @@ struct lang_type /* The number of virtual functions defined for this _CLASSTYPE node. */ #define CLASSTYPE_VSIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->vsize) -/* The virtual base classes that this type uses. */ +/* The list of binfos of virtual base classes that this type uses. */ #define CLASSTYPE_VBASECLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->vbases) /* The virtual function pointer fields that this type contains. */ #define CLASSTYPE_VFIELDS(NODE) (TYPE_LANG_SPECIFIC(NODE)->vfields) @@ -1161,22 +1177,21 @@ struct lang_decl_flags unsigned static_function : 1; unsigned const_memfunc : 1; unsigned volatile_memfunc : 1; - unsigned abstract_virtual : 1; unsigned permanent_attr : 1 ; - unsigned constructor_for_vbase_attr : 1; + unsigned mutable_flag : 1; unsigned is_default_implementation : 1; unsigned saved_inline : 1; unsigned use_template : 2; - unsigned nonconverting : 1; unsigned declared_inline : 1; unsigned not_really_extern : 1; unsigned needs_final_overrider : 1; unsigned bitfield : 1; unsigned defined_in_class : 1; - unsigned dummy : 4; + unsigned constructor_for_vbase_attr : 2; + unsigned dummy : 3; tree access; tree context; @@ -1222,9 +1237,35 @@ struct lang_decl #define DECL_CONV_FN_P(NODE) \ (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)) && TREE_TYPE (DECL_NAME (NODE))) -/* For FUNCTION_DECLs: nonzero means that this function is a constructor +#define CONSTRUCTOR_FOR_VBASE 1 +#define CONSTRUCTOR_FOR_PVBASE 2 +#define DESTRUCTOR_FOR_PVBASE 3 + +/* For FUNCTION_DECLs: nonzero means that this function is a con/destructor for an object with virtual baseclasses. */ -#define DECL_CONSTRUCTOR_FOR_VBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr) +#define DECL_CONSTRUCTOR_FOR_VBASE(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr) + +/* Nonzero means that this function is a constructor for an object + with virtual baseclasses. */ +#define DECL_CONSTRUCTOR_FOR_VBASE_P(NODE) \ + (DECL_CONSTRUCTOR_FOR_VBASE (NODE) == CONSTRUCTOR_FOR_VBASE) + +/* Nonzero means that this function is a constructor for an object + with virtual baseclasses which have virtual functions. */ +#define DECL_CONSTRUCTOR_FOR_PVBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr == CONSTRUCTOR_FOR_PVBASE) + +/* Nonzero means that this function is a destructor for an object + with virtual baseclasses which have virtual functions. */ +#define DECL_DESTRUCTOR_FOR_PVBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr == DESTRUCTOR_FOR_PVBASE) + +/* Nonzero means that this function is a wrapper around a PVBASE ctor. */ +#define DECL_VLIST_CTOR_WRAPPER_P(NODE) \ + (DECL_CONSTRUCTOR_FOR_VBASE_P (NODE) && DECL_VLIST_CTOR_WRAPPED (NODE)\ + && TREE_CODE (DECL_VLIST_CTOR_WRAPPED (NODE)) == FUNCTION_DECL \ + && DECL_CONSTRUCTOR_FOR_PVBASE_P (DECL_VLIST_CTOR_WRAPPED (NODE))) + +/* Refers to original function that NODE wraps. */ +#define DECL_VLIST_CTOR_WRAPPED(NODE) DECL_MEMFUNC_POINTER_TO (NODE) /* Non-zero for a FUNCTION_DECL that declares a type-info function. */ #define DECL_TINFO_FN_P(NODE) \ @@ -1327,6 +1368,10 @@ struct lang_decl (DECL_CONTEXT (NODE) ? DECL_CONTEXT (NODE) : global_namespace) #define FROB_CONTEXT(NODE) ((NODE) == global_namespace ? NULL_TREE : (NODE)) +/* For a virtual function, the base where we find its vtable entry. + For a non-virtual function, the base where it is defined. */ +#define DECL_VIRTUAL_CONTEXT(NODE) DECL_CONTEXT (NODE) + /* 1 iff NODE has namespace scope, including the global namespace. */ #define DECL_NAMESPACE_SCOPE_P(NODE) \ (DECL_CONTEXT (NODE) == NULL_TREE \ @@ -2099,6 +2144,7 @@ extern void decl_attributes PROTO((tree, tree, tree)); extern void init_function_format_info PROTO((void)); extern void record_function_format PROTO((tree, tree, int, int, int)); extern void check_function_format PROTO((tree, tree, tree)); +extern void check_function_bounds PROTO((tree, tree, tree)); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ extern void binary_op_error PROTO((enum tree_code)); @@ -2160,6 +2206,7 @@ extern tree delta2_identifier; extern tree pfn_or_delta2_identifier; extern tree tag_identifier; extern tree vt_off_identifier; +extern tree in_charge_identifier; /* A node that is a list (length 1) of error_mark_nodes. */ extern tree error_mark_list; @@ -2169,6 +2216,8 @@ extern tree class_type_node, record_type_node, union_type_node, enum_type_node; extern tree unknown_type_node; extern tree opaque_type_node, signature_type_node; +extern tree vlist_identifier, vlist_type_node, vlist_zero_node; + /* Node for "pointer to (virtual) function". This may be distinct from ptr_type_node so gdb can distinguish them. */ #define vfunc_ptr_type_node \ @@ -2242,6 +2291,9 @@ extern int current_class_depth; extern tree current_lang_name; extern tree lang_name_cplusplus, lang_name_c, lang_name_java; +/* The low-water mark on the class-cache obstack. */ +extern char *class_cache_firstobj; + /* Points to the name of that function. May not be the DECL_NAME of CURRENT_FUNCTION_DECL due to overloading */ extern tree original_function_name; @@ -2281,6 +2333,8 @@ extern int current_function_parms_stored; #define AUTO_TEMP_FORMAT "_$tmp_%d" #define VTABLE_BASE "$vb" #define VTABLE_NAME_FORMAT (flag_vtable_thunks ? "__vt_%s" : "_vt$%s") +#define VCTABLE_NAME "__vc$" +#define VLIST_NAME_FORMAT "__vl$%s" #define VFIELD_BASE "$vf" #define VFIELD_NAME "_vptr$" #define VFIELD_NAME_FORMAT "_vptr$%s" @@ -2303,6 +2357,8 @@ extern int current_function_parms_stored; #define AUTO_TEMP_FORMAT "_.tmp_%d" #define VTABLE_BASE ".vb" #define VTABLE_NAME_FORMAT (flag_vtable_thunks ? "__vt_%s" : "_vt.%s") +#define VCTABLE_NAME "__vc." +#define VLIST_NAME_FORMAT "__vl.%s" #define VFIELD_BASE ".vf" #define VFIELD_NAME "_vptr." #define VFIELD_NAME_FORMAT "_vptr.%s" @@ -2335,6 +2391,8 @@ extern int current_function_parms_stored; #define VTABLE_NAME_P(ID_NODE) \ (!strncmp (IDENTIFIER_POINTER (ID_NODE), VTABLE_NAME, \ sizeof (VTABLE_NAME) - 1)) +#define VCTABLE_NAME "__vc_" +#define VLIST_NAME_FORMAT "__vl_%s" #define VFIELD_BASE "__vfb" #define VFIELD_NAME "__vptr_" #define VFIELD_NAME_P(ID_NODE) \ @@ -2368,6 +2426,9 @@ extern int current_function_parms_stored; #define DTOR_NAME "__dt" #define IN_CHARGE_NAME "__in_chrg" +#define VLIST_NAME "__vlist" +#define VLIST1_NAME "__vlist1" +#define VLIST_TYPE_NAME "6_Vlist" #define VTBL_PTR_TYPE "__vtbl_ptr_type" #define VTABLE_DELTA_NAME "__delta" @@ -2545,6 +2606,8 @@ extern tree current_class_name; /* IDENTIFIER_NODE: name of current class */ as well as the space of member functions. LOOKUP_HAS_IN_CHARGE means that the "in charge" variable is already in the parameter list. + LOOKUP_HAS_VLIST means that the "vlist" variable is already in + the parameter list. LOOKUP_ONLYCONVERTING means that non-conversion constructors are not tried. DIRECT_BIND means that if a temporary is created, it should be created so that it lives as long as the current variable bindings; otherwise it @@ -2583,6 +2646,7 @@ extern tree current_class_name; /* IDENTIFIER_NODE: name of current class */ #define LOOKUP_PREFER_NAMESPACES (4096) #define LOOKUP_PREFER_BOTH (6144) #define LOOKUP_TEMPLATES_EXPECTED (8192) +#define LOOKUP_HAS_VLIST (16384) #define LOOKUP_NAMESPACES_ONLY(f) \ (((f) & LOOKUP_PREFER_NAMESPACES) && !((f) & LOOKUP_PREFER_TYPES)) @@ -2733,7 +2797,7 @@ extern void push_lang_context PROTO((tree)); extern void pop_lang_context PROTO((void)); extern tree instantiate_type PROTO((tree, tree, int)); extern void print_class_statistics PROTO((void)); -extern void maybe_push_cache_obstack PROTO((void)); +extern void push_cache_obstack PROTO((void)); extern unsigned HOST_WIDE_INT skip_rtti_stuff PROTO((tree *, tree)); extern void build_self_reference PROTO((void)); extern void warn_hidden PROTO((tree)); @@ -3040,6 +3104,8 @@ extern tree build_x_delete PROTO((tree, int, tree)); extern tree build_delete PROTO((tree, tree, tree, int, int)); extern tree build_vbase_delete PROTO((tree, tree)); extern tree build_vec_delete PROTO((tree, tree, tree, tree, int)); +extern tree build_base_dtor_call PROTO((tree, tree, tree)); +extern void init_vlist PROTO((tree)); /* in input.c */ @@ -3106,13 +3172,15 @@ extern tree build_decl_overload_real PROTO((tree, tree, tree, tree, extern void set_mangled_name_for_decl PROTO((tree)); extern tree build_typename_overload PROTO((tree)); extern tree build_overload_with_type PROTO((tree, tree)); -extern tree build_destructor_name PROTO((tree)); +extern tree build_destructor_name PROTO((tree, int)); extern tree build_opfncall PROTO((enum tree_code, int, tree, tree, tree)); extern tree hack_identifier PROTO((tree, tree)); extern tree make_thunk PROTO((tree, int)); extern void emit_thunk PROTO((tree)); extern void synthesize_method PROTO((tree)); extern tree get_id_2 PROTO((char *, tree)); +extern tree get_vlist_vtable_id PROTO((tree, tree)); + /* in pt.c */ extern void check_template_shadow PROTO ((tree)); @@ -3189,6 +3257,7 @@ extern tree get_tinfo_fn_dynamic PROTO((tree)); extern tree build_typeid PROTO((tree)); extern tree build_x_typeid PROTO((tree)); extern tree get_tinfo_fn PROTO((tree)); +extern tree get_tinfo_fn_unused PROTO((tree)); extern tree get_typeid PROTO((tree)); extern tree get_typeid_1 PROTO((tree)); extern tree build_dynamic_cast PROTO((tree, tree)); @@ -3388,6 +3457,7 @@ extern tree maybe_dummy_object PROTO((tree, tree *)); extern int is_dummy_object PROTO((tree)); extern tree search_tree PROTO((tree, tree (*)(tree))); extern int cp_valid_lang_attribute PROTO((tree, tree, tree, tree)); +extern tree make_ptrmem_cst PROTO((tree, tree)); #define scratchalloc expralloc #define scratch_tree_cons expr_tree_cons diff --git a/gnu/egcs/gcc/cp/decl2.c b/gnu/egcs/gcc/cp/decl2.c index bb24014d790..6d0d8ec9fe9 100644 --- a/gnu/egcs/gcc/cp/decl2.c +++ b/gnu/egcs/gcc/cp/decl2.c @@ -224,14 +224,21 @@ int warn_long_long = 1; int warn_ctor_dtor_privacy = 1; -/* True if we want to implement vtables using "thunks". - The default is off. */ +/* 1 or 2 if we want to implement vtables using "thunks". + The default is off. Version 1 indicates "old" implementation; + Version 2 passes the __vlist argument in pvbase cases. */ #ifndef DEFAULT_VTABLE_THUNKS #define DEFAULT_VTABLE_THUNKS 0 #endif int flag_vtable_thunks = DEFAULT_VTABLE_THUNKS; +#if DEFAULT_VTABLE_THUNKS == 2 +int flag_vtable_thunks_compat = 1; +#else +int flag_vtable_thunks_compat = 0; +#endif + /* True if we want to deal with repository information. */ int flag_use_repository; @@ -282,6 +289,10 @@ int warn_sign_compare; int warn_format; +/* Warn about potential overruns in static buffers. */ + +int warn_bounded; + /* Warn about a subscript that has type char. */ int warn_char_subscripts; @@ -633,12 +644,43 @@ lang_decode_option (argc, argv) found = 1; cp_deprecated ("-fexternal-templates"); } + else if (!strncmp (p, "vtable-thunks", 13)) + { + if (p[13] == '=') + { + flag_vtable_thunks = + read_integral_parameter (p+14, p, 1); + } + else + { + /* If the machine file has a default setting, use that + for -fvtable-thunks. Otherwise, set it to version + 2. */ +#if DEFAULT_VTABLE_THUNKS + flag_vtable_thunks = DEFAULT_VTABLE_THUNKS; +#else + flag_vtable_thunks = 1; +#endif + } + if (flag_vtable_thunks == 2) + /* v2 is a compatibility mode between v1 and v3. */ + flag_vtable_thunks_compat = 1; + else if(flag_vtable_thunks == 3) + flag_vtable_thunks_compat = 0; + found = 1; + } + else if (!strcmp (p, "handle-signatures")) + { + flag_handle_signatures = 1; + found = 1; + cp_deprecated ("-fhandle-signatures"); + } else if (!strcmp (p, "new-abi")) { flag_new_abi = 1; flag_do_squangling = 1; flag_honor_std = 1; - flag_vtable_thunks = 1; + flag_vtable_thunks = 2; } else if (!strcmp (p, "no-new-abi")) { @@ -712,6 +754,8 @@ lang_decode_option (argc, argv) warn_sign_compare = setting; else if (!strcmp (p, "format")) warn_format = setting; + else if (!strcmp (p, "bounded")) + warn_bounded = setting; else if (!strcmp (p, "conversion")) warn_conversion = setting; else if (!strcmp (p, "parentheses")) @@ -759,6 +803,7 @@ lang_decode_option (argc, argv) warn_implicit = setting; warn_switch = setting; warn_format = setting; + warn_bounded = setting; warn_parentheses = setting; warn_missing_braces = setting; warn_sign_compare = setting; @@ -911,17 +956,27 @@ grok_x_components (specs) This function adds the "in-charge" flag to member function FN if appropriate. It is called from grokclassfn and tsubst. - FN must be either a constructor or destructor. */ + FN must be either a constructor or destructor. + + For vtable thunks, types with polymorphic virtual bases need an + additional "vlist" argument which is an array of virtual tables. + In addition, if backwards-compatibility to v1 thunks is requested, + a wrapper constructor may be needed as well. */ void maybe_retrofit_in_chrg (fn) tree fn; { tree basetype, arg_types, parms, parm, fntype; + tree wrapper; + + if (CLASSTYPE_IS_TEMPLATE (DECL_CLASS_CONTEXT (fn))) + /* Never retrofit arguments on template methods. */ + return; if (DECL_CONSTRUCTOR_P (fn) && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CLASS_CONTEXT (fn)) - && ! DECL_CONSTRUCTOR_FOR_VBASE_P (fn)) + && DECL_CONSTRUCTOR_FOR_VBASE (fn) == 0) /* OK */; else if (! DECL_CONSTRUCTOR_P (fn) && TREE_CHAIN (DECL_ARGUMENTS (fn)) == NULL_TREE) @@ -930,7 +985,41 @@ maybe_retrofit_in_chrg (fn) return; if (DECL_CONSTRUCTOR_P (fn)) - DECL_CONSTRUCTOR_FOR_VBASE_P (fn) = 1; + { + if (TYPE_USES_PVBASES (DECL_CLASS_CONTEXT (fn))) + { + DECL_CONSTRUCTOR_FOR_VBASE (fn) = CONSTRUCTOR_FOR_PVBASE; + if (flag_vtable_thunks_compat && varargs_function_p (fn)) + sorry ("-fvtable-thunks=2 for vararg constructor", fn); + } + else + DECL_CONSTRUCTOR_FOR_VBASE (fn) = CONSTRUCTOR_FOR_VBASE; + } + else if (TYPE_USES_PVBASES (DECL_CLASS_CONTEXT (fn))) + DECL_CONSTRUCTOR_FOR_VBASE (fn) = DESTRUCTOR_FOR_PVBASE; + + /* Retrieve the arguments, because it is potentially modified twice. */ + arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); + basetype = TREE_TYPE (TREE_VALUE (arg_types)); + arg_types = TREE_CHAIN (arg_types); + + if (DECL_CONSTRUCTOR_FOR_PVBASE_P (fn) + || DECL_DESTRUCTOR_FOR_PVBASE_P (fn)) + { + /* Add the __vlist argument first. See __in_chrg below. */ + tree id = vlist_identifier; + if (DECL_DESTRUCTOR_FOR_PVBASE_P (fn)) + id = get_identifier (VLIST1_NAME); + parm = build_decl (PARM_DECL, id, vlist_type_node); + SET_DECL_ARTIFICIAL (parm); + DECL_ARG_TYPE (parm) = vlist_type_node; + parms = DECL_ARGUMENTS (fn); + /* Add it after 'this'. */ + TREE_CHAIN (parm) = TREE_CHAIN (parms); + TREE_CHAIN (parms) = parm; + + arg_types = hash_tree_chain (vlist_type_node, arg_types); + } /* First add it to DECL_ARGUMENTS... */ parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); @@ -943,9 +1032,7 @@ maybe_retrofit_in_chrg (fn) TREE_CHAIN (parms) = parm; /* ...and then to TYPE_ARG_TYPES. */ - arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); - basetype = TREE_TYPE (TREE_VALUE (arg_types)); - arg_types = hash_tree_chain (integer_type_node, TREE_CHAIN (arg_types)); + arg_types = hash_tree_chain (integer_type_node, arg_types); fntype = build_cplus_method_type (basetype, TREE_TYPE (TREE_TYPE (fn)), arg_types); if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) @@ -1036,7 +1123,8 @@ grokclassfn (ctype, function, flags, quals) if (flags == DTOR_FLAG) { - DECL_ASSEMBLER_NAME (function) = build_destructor_name (ctype); + DECL_ASSEMBLER_NAME (function) = + build_destructor_name (ctype, DECL_DESTRUCTOR_FOR_PVBASE_P (function)); TYPE_HAS_DESTRUCTOR (ctype) = 1; } else @@ -2409,12 +2497,13 @@ mark_vtable_entries (decl) tree fnaddr; tree fn; - if (TREE_CODE (TREE_VALUE (entries)) == NOP_EXPR) + fnaddr = (flag_vtable_thunks ? TREE_VALUE (entries) + : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries))); + + if (TREE_CODE (fnaddr) == NOP_EXPR) /* RTTI offset. */ continue; - fnaddr = (flag_vtable_thunks ? TREE_VALUE (entries) - : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries))); fn = TREE_OPERAND (fnaddr, 0); TREE_ADDRESSABLE (fn) = 1; if (DECL_LANG_SPECIFIC (fn) && DECL_ABSTRACT_VIRTUAL_P (fn)) @@ -2478,9 +2567,13 @@ void maybe_make_one_only (decl) tree decl; { - /* This is not necessary on targets that support weak symbols, because - the implicit instantiations will defer to the explicit one. */ - if (! supports_one_only () || SUPPORTS_WEAK) + /* We used to say that this was not necessary on targets that support weak + symbols, because the implicit instantiations will defer to the explicit + one. However, that's not actually the case in SVR4; a strong definition + after a weak one is an error. Also, not making explicit + instantiations one_only means that we can end up with two copies of + some template instantiations. */ + if (! supports_one_only ()) return; /* We can't set DECL_COMDAT on functions, or finish_file will think @@ -2768,6 +2861,30 @@ import_export_decl (decl) else DECL_NOT_REALLY_EXTERN (decl) = 0; } + else if (DECL_VLIST_CTOR_WRAPPER_P (decl)) + { + int implement; + tree ctype = DECL_CLASS_CONTEXT (decl); + import_export_class (ctype); + if (!DECL_THIS_INLINE (DECL_VLIST_CTOR_WRAPPED (decl))) + { + /* No change. */ + } + else if (CLASSTYPE_INTERFACE_KNOWN (ctype)) + { + implement = !CLASSTYPE_INTERFACE_ONLY (ctype) + && flag_implement_inlines; + DECL_NOT_REALLY_EXTERN (decl) = implement; + DECL_EXTERNAL (decl) = !implement; + } + else + { + DECL_NOT_REALLY_EXTERN (decl) = 1; + DECL_EXTERNAL (decl) = 1; + } + if (flag_weak) + comdat_linkage (decl); + } else if (DECL_FUNCTION_MEMBER_P (decl)) { tree ctype = DECL_CLASS_CONTEXT (decl); @@ -2803,7 +2920,7 @@ import_export_decl (decl) since it will not be emitted when the vtable for the type is output (which is when the unqualified version is generated). */ - && ctype == TYPE_MAIN_VARIANT (ctype)) + && same_type_p (ctype, TYPE_MAIN_VARIANT (ctype))) { DECL_NOT_REALLY_EXTERN (decl) = ! (CLASSTYPE_INTERFACE_ONLY (ctype) @@ -2814,7 +2931,8 @@ import_export_decl (decl) if (flag_weak) comdat_linkage (decl); } - else if (TYPE_BUILT_IN (ctype) && ctype == TYPE_MAIN_VARIANT (ctype)) + else if (TYPE_BUILT_IN (ctype) + && same_type_p (ctype, TYPE_MAIN_VARIANT (ctype))) DECL_NOT_REALLY_EXTERN (decl) = 0; else comdat_linkage (decl); @@ -3087,7 +3205,7 @@ start_static_storage_duration_function () /* Start the function itself. This is equivalent to declarating the function as: - static inline void __ssdf (int __initialize_p, init __priority_p); + static void __ssdf (int __initialize_p, init __priority_p); It is static because we only need to call this function from the various constructor and destructor functions for this module. */ @@ -3519,6 +3637,33 @@ generate_ctor_and_dtor_functions_for_priority (n, data) return 0; } +/* Returns non-zero if T is a vlist ctor wrapper. */ + +static int +vlist_ctor_wrapper_p (t, data) + tree t; + void *data ATTRIBUTE_UNUSED; +{ + return (TREE_CODE (t) == FUNCTION_DECL) && DECL_VLIST_CTOR_WRAPPER_P (t); +} + +/* Emits a vlist ctor wrapper if necessary. */ + +static int +finish_vlist_ctor_wrapper (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; +{ + import_export_decl (*t); + if (!DECL_EXTERNAL (*t) && !TREE_USED (*t)) + { + mark_used (*t); + synthesize_method (*t); + return 1; + } + return 0; +} + /* This routine is called from the last rule in yyparse (). Its job is to create all the code needed to initialize and destroy the global aggregates. We do the destruction @@ -3572,15 +3717,9 @@ finish_file () do { - /* We need to start a new initialization function each time - through the loop. That's because we need to know which - vtables have been referenced, and TREE_SYMBOL_REFERENCED - isn't computed until a function is finished, and written out. - That's a deficiency in the back-end. When this is fixed, - these initialization functions could all become inline, with - resulting performance improvements. */ - start_static_storage_duration_function (); - push_to_top_level (); + /* Non-zero if we need a static storage duration function on + this iteration through the loop. */ + int need_ssdf_p = 0; reconsider = 0; @@ -3601,10 +3740,12 @@ finish_file () /*data=*/0)) reconsider = 1; - /* Come back to the static storage duration function; we're - about to emit instructions there for static initializations - and such. */ - pop_from_top_level (); + if (walk_globals (vlist_ctor_wrapper_p, + finish_vlist_ctor_wrapper, + /*data=*/0)) + reconsider = 1; + + /* The list of objects with static storage duration is built up in reverse order, so we reverse it here. We also clear STATIC_AGGREGATES so that any new aggregates added during the @@ -3616,6 +3757,20 @@ finish_file () { if (! TREE_ASM_WRITTEN (TREE_VALUE (vars))) rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1); + if (!need_ssdf_p) + { + /* We need to start a new initialization function each + time through the loop. That's because we need to + know which vtables have been referenced, and + TREE_SYMBOL_REFERENCED isn't computed until a + function is finished, and written out. That's a + deficiency in the back-end. When this is fixed, + these initialization functions could all become + inline, with resulting performance improvements. */ + start_static_storage_duration_function (); + need_ssdf_p = 1; + } + do_static_initialization_and_destruction (TREE_VALUE (vars), TREE_PURPOSE (vars)); reconsider = 1; @@ -3624,7 +3779,8 @@ finish_file () /* Finish up the static storage duration function for this round. */ - finish_static_storage_duration_function (); + if (need_ssdf_p) + finish_static_storage_duration_function (); /* Go through the various inline functions, and see if any need synthesizing. */ @@ -3807,7 +3963,8 @@ reparse_absdcl_as_casts (decl, expr) expr = build_c_cast (type, expr); } - if (warn_old_style_cast) + if (warn_old_style_cast && ! in_system_header + && current_lang_name != lang_name_c) warning ("use of old-style cast"); return expr; @@ -3981,7 +4138,7 @@ build_expr_from_tree (t) else { tree fn = TREE_OPERAND (t, 0); - + /* We can get a TEMPLATE_ID_EXPR here on code like: x->f<2>(); @@ -3992,7 +4149,9 @@ build_expr_from_tree (t) build_expr_from_tree. So, just use build_expr_from_tree when we really need it. */ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) - fn = build_expr_from_tree (fn); + fn = lookup_template_function + (TREE_OPERAND (fn, 0), + build_expr_from_tree (TREE_OPERAND (fn, 1))); return build_method_call (build_expr_from_tree (TREE_OPERAND (t, 1)), @@ -4481,6 +4640,12 @@ set_decl_namespace (decl, scope, friendp) /* Since decl is a function, old should contain a function decl. */ if (!is_overloaded_fn (old)) goto complain; + if (processing_template_decl || processing_specialization) + /* We have not yet called push_template_decl to turn the + FUNCTION_DECL into a TEMPLATE_DECL, so the declarations + won't match. But, we'll check later, when we construct the + template. */ + return; for (; old; old = OVL_NEXT (old)) if (decls_match (decl, OVL_CURRENT (old))) return; @@ -4870,11 +5035,19 @@ lookup_arg_dependent (name, fns, args) tree args; { struct arg_lookup k; + k.name = name; k.functions = fns; - k.namespaces = NULL_TREE; k.classes = NULL_TREE; - + + /* Note that we've already looked at the current namespace during normal + unqualified lookup, unless we found a decl in function scope. */ + if (fns && ! TREE_PERMANENT (OVL_CURRENT (fns))) + k.namespaces = NULL_TREE; + else + k.namespaces = scratch_tree_cons (current_decl_namespace (), + NULL_TREE, NULL_TREE); + push_scratch_obstack (); arg_assoc_args (&k, args); pop_obstacks (); diff --git a/gnu/egcs/gcc/cp/typeck.c b/gnu/egcs/gcc/cp/typeck.c index 4822dbda4ea..def2615ccee 100644 --- a/gnu/egcs/gcc/cp/typeck.c +++ b/gnu/egcs/gcc/cp/typeck.c @@ -1355,8 +1355,13 @@ comp_target_parms (parms1, parms2, strict) if (t1 == 0 && t2 != 0) { - cp_pedwarn ("ANSI C++ prohibits conversion from `(%#T)' to `(...)'", - parms2); + if (! flag_strict_prototype && t2 == void_list_node) + /* t1 might be the arglist of a function pointer in extern "C" + declared to take (), which we fudged to (...). Don't make the + user pay for our mistake. */; + else + cp_pedwarn ("ANSI C++ prohibits conversion from `%#T' to `(...)'", + parms2); return self_promoting_args_p (t2); } if (t2 == 0) @@ -1609,6 +1614,11 @@ c_sizeof (type) t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (TYPE_PRECISION (char_type_node))); t = convert (sizetype, t); + + /* Keep track if the sizeof is of a pointer */ + if (code == POINTER_TYPE) + SIZEOF_PTR_DERIVED (t) = 1; + /* size_binop does not put the constant in range, so do it now. */ if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0)) TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1; @@ -1669,6 +1679,11 @@ c_sizeof_nowarn (type) t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (TYPE_PRECISION (char_type_node))); t = convert (sizetype, t); + + /* Keep track if the sizeof is of a pointer */ + if (code == POINTER_TYPE) + SIZEOF_PTR_DERIVED (t) = 1; + force_fit_type (t, 0); return t; } @@ -3021,6 +3036,9 @@ build_function_call_real (function, params, require_complete, flags) if (warn_format && (name || assembler_name)) check_function_format (name, assembler_name, coerced_params); + if (warn_bounded && (name || assembler_name)) + check_function_bounds (name, assembler_name, coerced_params); + /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c to do something useful. */ @@ -4912,9 +4930,7 @@ unary_complex_lvalue (code, arg) type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t)); type = build_pointer_type (type); - t = make_node (PTRMEM_CST); - TREE_TYPE (t) = type; - PTRMEM_CST_MEMBER (t) = TREE_OPERAND (arg, 1); + t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1)); return t; } } @@ -5079,17 +5095,20 @@ build_conditional_expr (ifexp, op1, op2) ifexp = op1 = save_expr (ifexp); } + type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + type2 = TREE_TYPE (op2); + code2 = TREE_CODE (type2); + if (op1 == error_mark_node || op2 == error_mark_node + || type1 == error_mark_node || type2 == error_mark_node) + return error_mark_node; + ifexp = cp_convert (boolean_type_node, ifexp); if (TREE_CODE (ifexp) == ERROR_MARK) return error_mark_node; /* C++: REFERENCE_TYPES must be dereferenced. */ - type1 = TREE_TYPE (op1); - code1 = TREE_CODE (type1); - type2 = TREE_TYPE (op2); - code2 = TREE_CODE (type2); - if (code1 == REFERENCE_TYPE) { op1 = convert_from_reference (op1); @@ -6359,7 +6378,12 @@ build_x_modify_expr (lhs, modifycode, rhs) /* Get difference in deltas for different pointer to member function types. Return integer_zero_node, if FROM cannot be converted to a - TO type. If FORCE is true, then allow reverse conversions as well. */ + TO type. If FORCE is true, then allow reverse conversions as well. + + Note that the naming of FROM and TO is kind of backwards; the return + value is what we add to a TO in order to get a FROM. They are named + this way because we call this function to find out how to convert from + a pointer to member of FROM to a pointer to member of TO. */ static tree get_delta_difference (from, to, force) @@ -6515,15 +6539,15 @@ build_ptrmemfunc (type, pfn, force) tree type, pfn; int force; { - tree idx = integer_zero_node; - tree delta = integer_zero_node; - tree delta2 = integer_zero_node; - tree npfn = NULL_TREE; tree fn; /* Handle multiple conversions of pointer to member functions. */ if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn))) { + tree idx = integer_zero_node; + tree delta = integer_zero_node; + tree delta2 = integer_zero_node; + tree npfn = NULL_TREE; tree ndelta, ndelta2; tree e1, e2, e3, n; tree pfn_type; @@ -6537,18 +6561,42 @@ build_ptrmemfunc (type, pfn, force) && comp_target_types (type, pfn_type, 1) != 1) cp_error ("conversion to `%T' from `%T'", type, pfn_type); - ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0)); - ndelta2 = cp_convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn)); - idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0); + if (TREE_CODE (pfn) == PTRMEM_CST) + { + /* We could just build the resulting CONSTRUCTOR now, but we + don't, relying on the general machinery below, together + with constant-folding, to do the right thing. We don't + want to return a PTRMEM_CST here, even though we could, + because a pointer-to-member constant ceases to be a + constant (from the point of view of the language) when it + is cast to another type. */ + + expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2); + if (npfn) + /* This constant points to a non-virtual function. + NDELTA2 will be NULL, but it's value doesn't really + matter since we won't use it anyhow. */ + ndelta2 = integer_zero_node; + } + else + { + ndelta = cp_convert (ptrdiff_type_node, + build_component_ref (pfn, + delta_identifier, + NULL_TREE, 0)); + ndelta2 = cp_convert (ptrdiff_type_node, + DELTA2_FROM_PTRMEMFUNC (pfn)); + idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0); + } n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (pfn_type)), TYPE_METHOD_BASETYPE (TREE_TYPE (type)), force); - delta = build_binary_op (PLUS_EXPR, ndelta, n); delta2 = build_binary_op (PLUS_EXPR, ndelta2, n); e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node)); + /* If it's a virtual function, this is what we want. */ e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, NULL_TREE, delta2); @@ -6556,8 +6604,10 @@ build_ptrmemfunc (type, pfn, force) npfn = build1 (NOP_EXPR, type, pfn); TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn); - e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, - NULL_TREE); + /* But if it's a non-virtual function, or NULL, we use this + instead. */ + e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, + idx, npfn, NULL_TREE); return build_conditional_expr (e1, e2, e3); } @@ -6575,10 +6625,7 @@ build_ptrmemfunc (type, pfn, force) fn = TREE_OPERAND (pfn, 0); my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0); - npfn = make_node (PTRMEM_CST); - TREE_TYPE (npfn) = build_ptrmemfunc_type (type); - PTRMEM_CST_MEMBER (npfn) = fn; - return npfn; + return make_ptrmem_cst (build_ptrmemfunc_type (type), fn); } /* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST @@ -6594,38 +6641,41 @@ expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2) { tree type = TREE_TYPE (cst); tree fn = PTRMEM_CST_MEMBER (cst); + tree ptr_class, fn_class; my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0); - - *delta - = get_delta_difference (TYPE_METHOD_BASETYPE - (TREE_TYPE (fn)), - TYPE_PTRMEMFUNC_OBJECT_TYPE (type), - /*force=*/0); + + /* The class that the function belongs to. */ + fn_class = DECL_CLASS_CONTEXT (fn); + + /* The class that we're creating a pointer to member of. */ + ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type); + + /* First, calculate the adjustment to the function's class. */ + *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0); + if (!DECL_VIRTUAL_P (fn)) { - *idx = size_binop (MINUS_EXPR, integer_zero_node, - integer_one_node); - *pfn = build_addr_func (fn); - if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)), - TYPE_PTRMEMFUNC_OBJECT_TYPE (type))) - *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type), - *pfn); + *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node); + *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn)); *delta2 = NULL_TREE; } else { - *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), - integer_one_node); + /* If we're dealing with a virtual function, we have to adjust 'this' + again, to point to the base which provides the vtable entry for + fn; the call will do the opposite adjustment. */ + tree orig_class = DECL_VIRTUAL_CONTEXT (fn); + tree binfo = binfo_or_else (orig_class, fn_class); + *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo)); + + /* Map everything down one to make room for the null PMF. */ + *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node); *pfn = NULL_TREE; - *delta2 = get_binfo (DECL_CONTEXT (fn), - DECL_CLASS_CONTEXT (fn), - 0); - *delta2 = get_vfield_offset (*delta2); - *delta2 = size_binop (PLUS_EXPR, *delta2, - build_binary_op (PLUS_EXPR, - *delta, - integer_zero_node)); + + /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS. */ + *delta2 = size_binop (PLUS_EXPR, *delta, + get_vfield_offset (TYPE_BINFO (orig_class))); } } @@ -7329,7 +7379,7 @@ c_expand_return (retval) || DECL_NAME (current_function_decl) == ansi_opname[(int) VEC_NEW_EXPR]) && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl)) && null_ptr_cst_p (retval)) - cp_pedwarn ("operator new should throw an exception, not return NULL"); + cp_warning ("operator new should throw an exception, not return NULL"); if (retval == NULL_TREE) { diff --git a/gnu/egcs/gcc/fold-const.c b/gnu/egcs/gcc/fold-const.c index 6acbe0baf34..52d3d68331b 100644 --- a/gnu/egcs/gcc/fold-const.c +++ b/gnu/egcs/gcc/fold-const.c @@ -1,5 +1,6 @@ /* Fold a constant sub-tree into a single node for C-compiler - Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -1304,6 +1305,10 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); int overflow = 0; int no_overflow = 0; + int sizeof_flag = 0; + + if (SIZEOF_PTR_DERIVED (arg1) == 1 || SIZEOF_PTR_DERIVED (arg2) == 1) + sizeof_flag = 1; int1l = TREE_INT_CST_LOW (arg1); int1h = TREE_INT_CST_HIGH (arg1); @@ -1475,6 +1480,10 @@ int_const_binop (code, arg1, arg2, notrunc, forsize) TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2)); + + if (sizeof_flag == 1) + SIZEOF_PTR_DERIVED (t) = 1; + return t; } @@ -2131,7 +2140,7 @@ operand_equal_p (arg0, arg1, only_const) case STRING_CST: return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) - && ! strncmp (TREE_STRING_POINTER (arg0), + && ! memcmp (TREE_STRING_POINTER (arg0), TREE_STRING_POINTER (arg1), TREE_STRING_LENGTH (arg0))); @@ -2177,6 +2186,12 @@ operand_equal_p (arg0, arg1, only_const) TREE_OPERAND (arg1, 0), 0)); case 'r': + /* If either of the pointer (or reference) expressions we are dereferencing + contain a side effect, these cannot be equal. */ + if (TREE_SIDE_EFFECTS (arg0) + || TREE_SIDE_EFFECTS (arg1)) + return 0; + switch (TREE_CODE (arg0)) { case INDIRECT_REF: @@ -3253,8 +3268,17 @@ make_range (exp, pin_p, plow, phigh) low = range_binop (PLUS_EXPR, type, n_high, 0, integer_one_node, 0); high = range_binop (MINUS_EXPR, type, n_low, 0, - integer_one_node, 0); - in_p = ! in_p; + integer_one_node, 0); + + /* If the range is of the form +/- [ x+1, x ], we won't + be able to normalize it. But then, it represents the + whole range or the empty set, so make it +/- [ -, - ]. + */ + if (tree_int_cst_equal (n_low, low) + && tree_int_cst_equal (n_high, high)) + low = high = 0; + else + in_p = ! in_p; } else low = n_low, high = n_high; @@ -3806,11 +3830,10 @@ fold_truthop (code, truth_type, lhs, rhs) { if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask)) { - /* Do not sign extend the constant here. The left operand - is either always unsigned or there is a BIT_AND_EXPR that - masks out the extension bits. */ - if (! (ll_unsignedp || ll_and_mask != 0)) - abort (); + /* Make the left operand unsigned, since we are only interested + in the value of one bit. Otherwise we are doing the wrong + thing below. */ + ll_unsignedp = 1; l_const = ll_mask; } else @@ -3822,8 +3845,7 @@ fold_truthop (code, truth_type, lhs, rhs) { if (r_const && integer_zerop (r_const) && integer_pow2p (rl_mask)) { - if (! (rl_unsignedp || rl_and_mask != 0)) - abort (); + rl_unsignedp = 1; r_const = rl_mask; } else @@ -4650,6 +4672,9 @@ fold (expr) | force_fit_type (t, overflow && !TREE_UNSIGNED (type))); TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0); + /* If arg0 was calculated from sizeof(ptr), record this */ + if (SIZEOF_PTR_DERIVED (arg0)) + SIZEOF_PTR_DERIVED (t) = 1; } else if (TREE_CODE (arg0) == REAL_CST) t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); @@ -4683,6 +4708,9 @@ fold (expr) | force_fit_type (t, overflow)); TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0); + /* If arg0 was calculated from sizeof(ptr), record this */ + if (SIZEOF_PTR_DERIVED (arg0)) + SIZEOF_PTR_DERIVED (t) = 1; } } else if (TREE_CODE (arg0) == REAL_CST) @@ -5621,7 +5649,15 @@ fold (expr) tree newconst = fold (build (PLUS_EXPR, TREE_TYPE (varop), constop, TREE_OPERAND (varop, 1))); - TREE_SET_CODE (varop, PREINCREMENT_EXPR); + + /* Do not overwrite the current varop to be a preincrement, + create a new node so that we won't confuse our caller who + might create trees and throw them away, reusing the + arguments that they passed to build. This shows up in + the THEN or ELSE parts of ?: being postincrements. */ + varop = build (PREINCREMENT_EXPR, TREE_TYPE (varop), + TREE_OPERAND (varop, 0), + TREE_OPERAND (varop, 1)); /* If VAROP is a reference to a bitfield, we must mask the constant by the width of the field. */ @@ -5665,9 +5701,9 @@ fold (expr) } - t = build (code, type, TREE_OPERAND (t, 0), - TREE_OPERAND (t, 1)); - TREE_OPERAND (t, constopnum) = newconst; + t = build (code, type, + (constopnum == 0) ? newconst : varop, + (constopnum == 1) ? newconst : varop); return t; } } @@ -5680,7 +5716,15 @@ fold (expr) tree newconst = fold (build (MINUS_EXPR, TREE_TYPE (varop), constop, TREE_OPERAND (varop, 1))); - TREE_SET_CODE (varop, PREDECREMENT_EXPR); + + /* Do not overwrite the current varop to be a predecrement, + create a new node so that we won't confuse our caller who + might create trees and throw them away, reusing the + arguments that they passed to build. This shows up in + the THEN or ELSE parts of ?: being postdecrements. */ + varop = build (PREDECREMENT_EXPR, TREE_TYPE (varop), + TREE_OPERAND (varop, 0), + TREE_OPERAND (varop, 1)); if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF && DECL_BIT_FIELD(TREE_OPERAND @@ -5719,9 +5763,9 @@ fold (expr) } - t = build (code, type, TREE_OPERAND (t, 0), - TREE_OPERAND (t, 1)); - TREE_OPERAND (t, constopnum) = newconst; + t = build (code, type, + (constopnum == 0) ? newconst : varop, + (constopnum == 1) ? newconst : varop); return t; } } diff --git a/gnu/egcs/gcc/toplev.c b/gnu/egcs/gcc/toplev.c index e98b4751a25..77abd5f6f3a 100644 --- a/gnu/egcs/gcc/toplev.c +++ b/gnu/egcs/gcc/toplev.c @@ -1064,6 +1064,8 @@ documented_lang_options[] = { "-Wno-conversion", "" }, { "-Wformat", "Warn about printf format anomalies" }, { "-Wno-format", "" }, + { "-Wbounded", "Warn about potential overruns in static buffers" }, + { "-Wno-bounded", "" }, { "-Wimplicit-function-declaration", "Warn about implicit function declarations" }, { "-Wno-implicit-function-declaration", "" }, diff --git a/gnu/egcs/gcc/tree.h b/gnu/egcs/gcc/tree.h index 0d7ea84aafc..b25c1cf8816 100644 --- a/gnu/egcs/gcc/tree.h +++ b/gnu/egcs/gcc/tree.h @@ -1,5 +1,6 @@ /* Front-end tree definitions for GNU compiler. - Copyright (C) 1989, 93-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. This file is part of GNU CC. @@ -24,6 +25,16 @@ Boston, MA 02111-1307, USA. */ struct rtx_def; #endif +/* Usage of TREE_LANG_FLAG_?: + 0: Not Used. + 1: Not Used. + 2: Not Used. + 3: Not Used. + 4: Not Used. + 5: Not Used. + 6: SIZEOF_PTR_DERIVED +*/ + /* Codes of tree nodes */ #define DEFTREECODE(SYM, STRING, TYPE, NARGS) SYM, @@ -546,6 +557,10 @@ struct tree_common #define TREE_LANG_FLAG_4(NODE) ((NODE)->common.lang_flag_4) #define TREE_LANG_FLAG_5(NODE) ((NODE)->common.lang_flag_5) #define TREE_LANG_FLAG_6(NODE) ((NODE)->common.lang_flag_6) + +/* Used to track constants derived from sizeof(pointer) operations */ +#define SIZEOF_PTR_DERIVED(NODE) (TREE_LANG_FLAG_6((NODE))) + /* Define additional fields and accessors for nodes representing constants. */ @@ -2207,6 +2222,7 @@ extern tree reorder_blocks PROTO ((tree *, tree, struct rtx_def *)); extern void free_temps_for_rtl_expr PROTO ((tree)); extern void instantiate_virtual_regs PROTO ((tree, struct rtx_def *)); +extern void unshare_all_rtl PROTO ((tree, struct rtx_def *)); extern int max_parm_reg_num PROTO ((void)); extern void push_function_context PROTO ((void)); extern void pop_function_context PROTO ((void)); -- cgit v1.2.3