This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH RFA: Tweak vec.[ch] to avoid undefined signed overflow
- From: Ian Lance Taylor <iant at google dot com>
- To: nathan at codesourcery dot com
- Cc: gcc-patches at gcc dot gnu dot org
- Date: 16 Jan 2007 08:28:03 -0800
- Subject: PATCH RFA: Tweak vec.[ch] to avoid undefined signed overflow
My ongoing work on producing a warning for cases where gcc relies on
undefined signed overflow produces warnings for vec.h. They arise
because of the way that VEC_reserve uses a negative size to request an
exact reservation. The code looks like this:
int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), \
alloc_ < 0 ? -alloc_ : alloc_ \
VEC_CHECK_PASS); \
The conditional is optimized into abs (alloc_). Within the called
function VEC_OP (T,base,space) we see this:
VEC_ASSERT (alloc_ >= 0, "space", T, base); \
Here alloc_ is abs (alloc_) from the caller. When VRP sees that the
result of abs in a test >= 0, it eliminates the test.
So that all seems fine. But, we have to consider INT_MIN. abs
(INT_MIN) is, of course, INT_MIN, which is a case of signed overflow.
The assumption made by VRP that abs (X) >= 0 is a case in which gcc
relies on the fact that signed overflow is undefined.
The effect here is that if some code ever manages to erroneously pass
INT_MIN to VEC_reserve, it will not get caught by the assert in VEC_OP
(t,base,space), because that assert will be removed. It will
presumably be caught later when malloc fails.
There is no major issue here. But after some discussion and some
thought, I think this code should stop overloading negative values,
and simply use a different function when it needs to reserve an exact
size. I think this is slightly easier to understand and slightly more
efficient.
This patch passes bootstrap and testsuite run on i686-pc-linux-gnu.
OK for mainline?
Ian
gcc/ChangeLog:
2007-01-16 Ian Lance Taylor <iant@google.com>
* vec.h (VEC_reserve_exact): Define.
(vec_gc_p_reserve_exact): Declare.
(vec_gc_o_reserve_exact): Declare.
(vec_heap_p_reserve_exact): Declare.
(vec_heap_o_reserve_exact): Declare.
(VEC_OP (T,A,reserve_exact)): New static inline function, three
versions.
(VEC_OP (T,A,reserve)) [all versions]: Remove handling of
negative parameter.
(VEC_OP (T,A,alloc)) [all versions]: Call ...reserve_exact.
(VEC_OP (T,A,copy)) [all versions]: Likewise.
(VEC_OP (T,a,safe_grow)) [all versions]: Likewise.
* vec.c (calculate_allocation): Add exact parameter. Change all
callers.
(vec_gc_o_reserve_1): New static function, from vec_gc_o_reserve.
(vec_gc_p_reserve, vec_gc_o_reserve): Call vec_gc_o_reserve_1.
(vec_gc_p_reserve_exact, vec_gc_o_reserve_exact): New functions.
(vec_heap_o_reserve_1): New static function, from vec_heap_o_reserve.
(vec_heap_p_reserve, vec_heap_o_reserve): Call vec_heap_o_reserve_1.
(vec_heap_p_reserve_exact): New function.
(vec_heap_o_reserve_exact): New function.
gcc/cp/ChangeLog:
2007-01-16 Ian Lance Taylor <iant@google.com>
* class.c (add_method): Call VEC_reserve_exact rather than passing
a negative size to VEC_reserve.
Index: gcc/vec.h
===================================================================
--- gcc/vec.h (revision 120782)
+++ gcc/vec.h (working copy)
@@ -66,8 +66,8 @@ Software Foundation, 51 Franklin Street,
least as many elements as you ask for, it will exponentially
increase if there are too few spare slots. If you want reserve a
specific number of slots, but do not want the exponential increase
- (for instance, you know this is the last allocation), use a
- negative number for reservation. You can also create a vector of a
+ (for instance, you know this is the last allocation), use the
+ reserve_exact operation. You can also create a vector of a
specific size from the get go.
You should prefer the push and pop operations, as they append and
@@ -238,16 +238,25 @@ Software Foundation, 51 Franklin Street,
/* Reserve space.
int VEC_T_A_reserve(VEC(T,A) *&v, int reserve);
- Ensure that V has at least abs(RESERVE) slots available. The
- signedness of RESERVE determines the reallocation behavior. A
- negative value will not create additional headroom beyond that
- requested. A positive value will create additional headroom. Note
- this can cause V to be reallocated. Returns nonzero iff
- reallocation actually occurred. */
+ Ensure that V has at least RESERVE slots available. This will
+ create additional headroom. Note this can cause V to be
+ reallocated. Returns nonzero iff reallocation actually
+ occurred. */
#define VEC_reserve(T,A,V,R) \
(VEC_OP(T,A,reserve)(&(V),R VEC_CHECK_INFO MEM_STAT_INFO))
+/* Reserve space exactly.
+ int VEC_T_A_reserve_exact(VEC(T,A) *&v, int reserve);
+
+ Ensure that V has at least RESERVE slots available. This will not
+ create additional headroom. Note this can cause V to be
+ reallocated. Returns nonzero iff reallocation actually
+ occurred. */
+
+#define VEC_reserve_exact(T,A,V,R) \
+ (VEC_OP(T,A,reserve_exact)(&(V),R VEC_CHECK_INFO MEM_STAT_INFO))
+
/* Push object with no reallocation
T *VEC_T_quick_push (VEC(T) *v, T obj); // Integer
T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer
@@ -411,11 +420,17 @@ Software Foundation, 51 Franklin Street,
#if !IN_GENGTYPE
/* Reallocate an array of elements with prefix. */
extern void *vec_gc_p_reserve (void *, int MEM_STAT_DECL);
+extern void *vec_gc_p_reserve_exact (void *, int MEM_STAT_DECL);
extern void *vec_gc_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
+extern void *vec_gc_o_reserve_exact (void *, int, size_t, size_t
+ MEM_STAT_DECL);
extern void ggc_free (void *);
#define vec_gc_free(V) ggc_free (V)
extern void *vec_heap_p_reserve (void *, int MEM_STAT_DECL);
+extern void *vec_heap_p_reserve_exact (void *, int MEM_STAT_DECL);
extern void *vec_heap_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
+extern void *vec_heap_o_reserve_exact (void *, int, size_t, size_t
+ MEM_STAT_DECL);
#define vec_heap_free(V) free (V)
#if ENABLE_CHECKING
@@ -702,8 +717,8 @@ static inline unsigned VEC_OP (T,base,lo
static inline VEC(T,A) *VEC_OP (T,A,alloc) \
(int alloc_ MEM_STAT_DECL) \
{ \
- /* We must request exact size allocation, hence the negation. */ \
- return (VEC(T,A) *) vec_##A##_p_reserve (NULL, -alloc_ PASS_MEM_STAT); \
+ return (VEC(T,A) *) vec_##A##_p_reserve_exact (NULL, alloc_ \
+ PASS_MEM_STAT); \
} \
\
static inline void VEC_OP (T,A,free) \
@@ -721,9 +736,8 @@ static inline VEC(T,A) *VEC_OP (T,A,copy
\
if (len_) \
{ \
- /* We must request exact size allocation, hence the negation. */ \
- new_vec_ = (VEC (T,A) *)(vec_##A##_p_reserve \
- (NULL, -len_ PASS_MEM_STAT)); \
+ new_vec_ = (VEC (T,A) *)(vec_##A##_p_reserve_exact \
+ (NULL, len_ PASS_MEM_STAT)); \
\
new_vec_->base.num = len_; \
memcpy (new_vec_->base.vec, vec_->vec, sizeof (T) * len_); \
@@ -734,8 +748,7 @@ static inline VEC(T,A) *VEC_OP (T,A,copy
static inline int VEC_OP (T,A,reserve) \
(VEC(T,A) **vec_, int alloc_ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
- int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), \
- alloc_ < 0 ? -alloc_ : alloc_ \
+ int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), alloc_ \
VEC_CHECK_PASS); \
\
if (extend) \
@@ -744,14 +757,28 @@ static inline int VEC_OP (T,A,reserve)
return extend; \
} \
\
+static inline int VEC_OP (T,A,reserve_exact) \
+ (VEC(T,A) **vec_, int alloc_ VEC_CHECK_DECL MEM_STAT_DECL) \
+{ \
+ int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), alloc_ \
+ VEC_CHECK_PASS); \
+ \
+ if (extend) \
+ *vec_ = (VEC(T,A) *) vec_##A##_p_reserve_exact (*vec_, alloc_ \
+ PASS_MEM_STAT); \
+ \
+ return extend; \
+} \
+ \
static inline void VEC_OP (T,A,safe_grow) \
(VEC(T,A) **vec_, int size_ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
VEC_ASSERT (size_ >= 0 \
&& VEC_OP(T,base,length) VEC_BASE(*vec_) <= (unsigned)size_, \
"grow", T, A); \
- VEC_OP (T,A,reserve) (vec_, (int)(*vec_ ? VEC_BASE(*vec_)->num : 0) - size_ \
- VEC_CHECK_PASS PASS_MEM_STAT); \
+ VEC_OP (T,A,reserve_exact) (vec_, \
+ size_ - (int)(*vec_ ? VEC_BASE(*vec_)->num : 0) \
+ VEC_CHECK_PASS PASS_MEM_STAT); \
VEC_BASE (*vec_)->num = size_; \
} \
\
@@ -972,11 +999,10 @@ static inline unsigned VEC_OP (T,base,lo
static inline VEC(T,A) *VEC_OP (T,A,alloc) \
(int alloc_ MEM_STAT_DECL) \
{ \
- /* We must request exact size allocation, hence the negation. */ \
- return (VEC(T,A) *) vec_##A##_o_reserve (NULL, -alloc_, \
- offsetof (VEC(T,A),base.vec), \
- sizeof (T) \
- PASS_MEM_STAT); \
+ return (VEC(T,A) *) vec_##A##_o_reserve_exact (NULL, alloc_, \
+ offsetof (VEC(T,A),base.vec), \
+ sizeof (T) \
+ PASS_MEM_STAT); \
} \
\
static inline VEC(T,A) *VEC_OP (T,A,copy) (VEC(T,base) *vec_ MEM_STAT_DECL) \
@@ -986,9 +1012,8 @@ static inline VEC(T,A) *VEC_OP (T,A,copy
\
if (len_) \
{ \
- /* We must request exact size allocation, hence the negation. */ \
- new_vec_ = (VEC (T,A) *)(vec_##A##_o_reserve \
- (NULL, -len_, \
+ new_vec_ = (VEC (T,A) *)(vec_##A##_o_reserve_exact \
+ (NULL, len_, \
offsetof (VEC(T,A),base.vec), sizeof (T) \
PASS_MEM_STAT)); \
\
@@ -1009,8 +1034,7 @@ static inline void VEC_OP (T,A,free)
static inline int VEC_OP (T,A,reserve) \
(VEC(T,A) **vec_, int alloc_ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
- int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), \
- alloc_ < 0 ? -alloc_ : alloc_ \
+ int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), alloc_ \
VEC_CHECK_PASS); \
\
if (extend) \
@@ -1022,14 +1046,30 @@ static inline int VEC_OP (T,A,reserve)
return extend; \
} \
\
+static inline int VEC_OP (T,A,reserve_exact) \
+ (VEC(T,A) **vec_, int alloc_ VEC_CHECK_DECL MEM_STAT_DECL) \
+{ \
+ int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), alloc_ \
+ VEC_CHECK_PASS); \
+ \
+ if (extend) \
+ *vec_ = (VEC(T,A) *) vec_##A##_o_reserve_exact \
+ (*vec_, alloc_, \
+ offsetof (VEC(T,A),base.vec), \
+ sizeof (T) PASS_MEM_STAT); \
+ \
+ return extend; \
+} \
+ \
static inline void VEC_OP (T,A,safe_grow) \
(VEC(T,A) **vec_, int size_ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
VEC_ASSERT (size_ >= 0 \
&& VEC_OP(T,base,length) VEC_BASE(*vec_) <= (unsigned)size_, \
"grow", T, A); \
- VEC_OP (T,A,reserve) (vec_, (int)(*vec_ ? VEC_BASE(*vec_)->num : 0) - size_ \
- VEC_CHECK_PASS PASS_MEM_STAT); \
+ VEC_OP (T,A,reserve_exact) (vec_, \
+ size_ - (int)(*vec_ ? VEC_BASE(*vec_)->num : 0) \
+ VEC_CHECK_PASS PASS_MEM_STAT); \
VEC_BASE (*vec_)->num = size_; \
} \
\
@@ -1064,11 +1104,9 @@ static inline T *VEC_OP (T,A,safe_insert
static inline VEC(T,A) *VEC_OP (T,A,alloc) \
(int alloc_ MEM_STAT_DECL) \
{ \
- /* We must request exact size allocation, hence the negation. */ \
- return (VEC(T,A) *) vec_##A##_o_reserve (NULL, -alloc_, \
- offsetof (VEC(T,A),base.vec), \
- sizeof (T) \
- PASS_MEM_STAT); \
+ return (VEC(T,A) *) vec_##A##_o_reserve_exact \
+ (NULL, alloc_, offsetof (VEC(T,A),base.vec), \
+ sizeof (T) PASS_MEM_STAT); \
} \
\
static inline VEC(T,A) *VEC_OP (T,A,copy) (VEC(T,base) *vec_ MEM_STAT_DECL) \
@@ -1078,9 +1116,8 @@ static inline VEC(T,A) *VEC_OP (T,A,copy
\
if (len_) \
{ \
- /* We must request exact size allocation, hence the negation. */ \
- new_vec_ = (VEC (T,A) *)(vec_##A##_o_reserve \
- (NULL, -len_, \
+ new_vec_ = (VEC (T,A) *)(vec_##A##_o_reserve_exact \
+ (NULL, len_, \
offsetof (VEC(T,A),base.vec), sizeof (T) \
PASS_MEM_STAT)); \
\
@@ -1101,8 +1138,7 @@ static inline void VEC_OP (T,A,free)
static inline int VEC_OP (T,A,reserve) \
(VEC(T,A) **vec_, int alloc_ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
- int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), \
- alloc_ < 0 ? -alloc_ : alloc_ \
+ int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), alloc_ \
VEC_CHECK_PASS); \
\
if (extend) \
@@ -1114,14 +1150,29 @@ static inline int VEC_OP (T,A,reserve)
return extend; \
} \
\
+static inline int VEC_OP (T,A,reserve_exact) \
+ (VEC(T,A) **vec_, int alloc_ VEC_CHECK_DECL MEM_STAT_DECL) \
+{ \
+ int extend = !VEC_OP (T,base,space) (VEC_BASE(*vec_), alloc_ \
+ VEC_CHECK_PASS); \
+ \
+ if (extend) \
+ *vec_ = (VEC(T,A) *) vec_##A##_o_reserve_exact \
+ (*vec_, alloc_, offsetof (VEC(T,A),base.vec), \
+ sizeof (T) PASS_MEM_STAT); \
+ \
+ return extend; \
+} \
+ \
static inline void VEC_OP (T,A,safe_grow) \
(VEC(T,A) **vec_, int size_ VEC_CHECK_DECL MEM_STAT_DECL) \
{ \
VEC_ASSERT (size_ >= 0 \
&& VEC_OP(T,base,length) VEC_BASE(*vec_) <= (unsigned)size_, \
"grow", T, A); \
- VEC_OP (T,A,reserve) (vec_, (int)(*vec_ ? VEC_BASE(*vec_)->num : 0) - size_ \
- VEC_CHECK_PASS PASS_MEM_STAT); \
+ VEC_OP (T,A,reserve_exact) (vec_, \
+ size_ - (int)(*vec_ ? VEC_BASE(*vec_)->num : 0) \
+ VEC_CHECK_PASS PASS_MEM_STAT); \
VEC_BASE (*vec_)->num = size_; \
} \
\
Index: gcc/vec.c
===================================================================
--- gcc/vec.c (revision 120782)
+++ gcc/vec.c (working copy)
@@ -40,16 +40,17 @@ struct vec_prefix
void *vec[1];
};
-/* Calculate the new ALLOC value, making sure that abs(RESERVE) slots
- are free. If RESERVE < 0 grow exactly, otherwise grow
- exponentially. */
+/* Calculate the new ALLOC value, making sure that RESERVE slots are
+ free. If EXACT grow exactly, otherwise grow exponentially. */
static inline unsigned
-calculate_allocation (const struct vec_prefix *pfx, int reserve)
+calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact)
{
unsigned alloc = 0;
unsigned num = 0;
+ gcc_assert (reserve >= 0);
+
if (pfx)
{
alloc = pfx->alloc;
@@ -61,11 +62,11 @@ calculate_allocation (const struct vec_p
return 0;
/* We must have run out of room. */
- gcc_assert (alloc - num < (unsigned)(reserve < 0 ? -reserve : reserve));
+ gcc_assert (alloc - num < (unsigned) reserve);
- if (reserve < 0)
+ if (exact)
/* Exact size. */
- alloc = num + -reserve;
+ alloc = num + reserve;
else
{
/* Exponential growth. */
@@ -85,33 +86,95 @@ calculate_allocation (const struct vec_p
return alloc;
}
-/* Ensure there are at least abs(RESERVE) free slots in VEC. If
- RESERVE < 0 grow exactly, else grow exponentially. As a special
- case, if VEC is NULL, and RESERVE is 0, no vector will be created. */
+/* Ensure there are at least RESERVE free slots in VEC. If EXACT grow
+ exactly, else grow exponentially. As a special case, if VEC is
+ NULL and RESERVE is 0, no vector will be created. The vector's
+ trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
+ sized elements. */
+
+static void *
+vec_gc_o_reserve_1 (void *vec, int reserve, size_t vec_offset, size_t elt_size,
+ bool exact MEM_STAT_DECL)
+{
+ struct vec_prefix *pfx = vec;
+ unsigned alloc = alloc = calculate_allocation (pfx, reserve, exact);
+
+ if (!alloc)
+ return NULL;
+
+ vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
+ ((struct vec_prefix *)vec)->alloc = alloc;
+ if (!pfx)
+ ((struct vec_prefix *)vec)->num = 0;
+
+ return vec;
+}
+
+/* Ensure there are at least RESERVE free slots in VEC, growing
+ exponentially. If RESERVE < 0 grow exactly, else grow
+ exponentially. As a special case, if VEC is NULL, and RESERVE is
+ 0, no vector will be created. */
void *
vec_gc_p_reserve (void *vec, int reserve MEM_STAT_DECL)
{
- return vec_gc_o_reserve (vec, reserve,
- offsetof (struct vec_prefix, vec), sizeof (void *)
- PASS_MEM_STAT);
+ return vec_gc_o_reserve_1 (vec, reserve,
+ offsetof (struct vec_prefix, vec),
+ sizeof (void *), false
+ PASS_MEM_STAT);
+}
+
+/* Ensure there are at least RESERVE free slots in VEC, growing
+ exactly. If RESERVE < 0 grow exactly, else grow exponentially. As
+ a special case, if VEC is NULL, and RESERVE is 0, no vector will be
+ created. */
+
+void *
+vec_gc_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
+{
+ return vec_gc_o_reserve_1 (vec, reserve,
+ offsetof (struct vec_prefix, vec),
+ sizeof (void *), true
+ PASS_MEM_STAT);
}
-/* As vec_gc_p_reserve, but for object vectors. The vector's trailing
- array is at VEC_OFFSET offset and consists of ELT_SIZE sized
- elements. */
+/* As for vec_gc_p_reserve, but for object vectors. The vector's
+ trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
+ sized elements. */
void *
vec_gc_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
- MEM_STAT_DECL)
+ MEM_STAT_DECL)
+{
+ return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
+ PASS_MEM_STAT);
+}
+
+/* As for vec_gc_p_reserve_exact, but for object vectors. The
+ vector's trailing array is at VEC_OFFSET offset and consists of
+ ELT_SIZE sized elements. */
+
+void *
+vec_gc_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
+ size_t elt_size MEM_STAT_DECL)
+{
+ return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
+ PASS_MEM_STAT);
+}
+
+/* As for vec_gc_o_reserve_1, but for heap allocated vectors. */
+
+static void *
+vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
+ size_t elt_size, bool exact MEM_STAT_DECL)
{
struct vec_prefix *pfx = vec;
- unsigned alloc = alloc = calculate_allocation (pfx, reserve);
-
+ unsigned alloc = calculate_allocation (pfx, reserve, exact);
+
if (!alloc)
return NULL;
- vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
+ vec = xrealloc (vec, vec_offset + alloc * elt_size);
((struct vec_prefix *)vec)->alloc = alloc;
if (!pfx)
((struct vec_prefix *)vec)->num = 0;
@@ -124,9 +187,21 @@ vec_gc_o_reserve (void *vec, int reserve
void *
vec_heap_p_reserve (void *vec, int reserve MEM_STAT_DECL)
{
- return vec_heap_o_reserve (vec, reserve,
- offsetof (struct vec_prefix, vec), sizeof (void *)
- PASS_MEM_STAT);
+ return vec_heap_o_reserve_1 (vec, reserve,
+ offsetof (struct vec_prefix, vec),
+ sizeof (void *), false
+ PASS_MEM_STAT);
+}
+
+/* As for vec_gc_p_reserve_exact, but for heap allocated vectors. */
+
+void *
+vec_heap_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
+{
+ return vec_heap_o_reserve_1 (vec, reserve,
+ offsetof (struct vec_prefix, vec),
+ sizeof (void *), true
+ PASS_MEM_STAT);
}
/* As for vec_gc_o_reserve, but for heap allocated vectors. */
@@ -135,18 +210,18 @@ void *
vec_heap_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
MEM_STAT_DECL)
{
- struct vec_prefix *pfx = vec;
- unsigned alloc = calculate_allocation (pfx, reserve);
+ return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
+ PASS_MEM_STAT);
+}
- if (!alloc)
- return NULL;
-
- vec = xrealloc (vec, vec_offset + alloc * elt_size);
- ((struct vec_prefix *)vec)->alloc = alloc;
- if (!pfx)
- ((struct vec_prefix *)vec)->num = 0;
-
- return vec;
+/* As for vec_gc_o_reserve_exact, but for heap allocated vectors. */
+
+void *
+vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
+ size_t elt_size MEM_STAT_DECL)
+{
+ return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
+ PASS_MEM_STAT);
}
#if ENABLE_CHECKING
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c (revision 120782)
+++ gcc/cp/class.c (working copy)
@@ -1071,9 +1071,15 @@ add_method (tree type, tree method, tree
if (insert_p)
{
+ bool reallocated;
+
/* We only expect to add few methods in the COMPLETE_P case, so
just make room for one more method in that case. */
- if (VEC_reserve (tree, gc, method_vec, complete_p ? -1 : 1))
+ if (complete_p)
+ reallocated = VEC_reserve_exact (tree, gc, method_vec, 1);
+ else
+ reallocated = VEC_reserve (tree, gc, method_vec, 1);
+ if (reallocated)
CLASSTYPE_METHOD_VEC (type) = method_vec;
if (slot == VEC_length (tree, method_vec))
VEC_quick_push (tree, method_vec, overload);