From patchwork Wed Sep 27 10:46:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 145319 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:cae8:0:b0:403:3b70:6f57 with SMTP id r8csp2535437vqu; Wed, 27 Sep 2023 03:47:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFJFrA7S3XVoy/0A251F8wVTIRsKbEVKWmFrEB9J/cexQ07BYPGXQnyBNBKbMcPKsU3as8K X-Received: by 2002:a05:6512:2027:b0:4fe:8ba9:4c4 with SMTP id s7-20020a056512202700b004fe8ba904c4mr1147371lfs.59.1695811645198; Wed, 27 Sep 2023 03:47:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695811645; cv=none; d=google.com; s=arc-20160816; b=u/gmvaChtb46QsxeQYyPJhuC7gJqoPssnTOIpADB/jXEs+suIWGqn6LPqknCXaq5JC FLOjAKNmLCWYUfg2Or1q9VSklQLl6q6fJqNIhwnqv1laAWwJ2/QH+cf6QlVcubpWCQm1 fzZvXgpqsEdFVKwH8Xtge9MXXRRDjqctN58XOk5AF7VsRiPQfk4fE+9Lj7ijOG9ThQIL vUsLj179/0qrGHFkxqe61581lE9bH8iJCUxCFVMjBoUfZeTyjXFGBT+OBw0h/5r+Xhs9 q3NdC32nkK5lEjqFjzfDXkTNW2QWxTgnCZ5X1LMMyJdoJDAhk3qSN86T4TUAq4zxaMMr 1VKA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:reply-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-disposition:in-reply-to :mime-version:references:message-id:subject:cc:to:from:date :dkim-signature:dmarc-filter:delivered-to; bh=DPNS4O8oQeFbOG6/bRzs1jLgyhDNR5m27riFTjVY+uw=; fh=ryqPpboSWJwVPxEUP+dbwdXcSYVBzwq1YjpUFQ8jTb0=; b=Nhvxw7Bf7QObiI920v3JumX95KL5gcu482FHwl+3K9dJwoxLCLXjcZkQLB15I/CBQw yaX0nJ90F/k15JKKCjPtlWK7uFJG684OK6txPVeJUsDDC5/WiK+DvkSy9JrwveePkYRt 37qUvcM5DH07ti4WwF7RXydS8vLjdP5nwhXYSFr0SpXrzho/8BB7D0wa5d81EhZTquqk +94b9iYLw3qUvSVNuunmhuWzIQU0lhBZs6xrSdfQoedEhovSRueF2A9l3JbN0iHpGEhg EQjayOrqMz/k7k2aOZk2g+CKB3smIPqkHilsC29AivAOPMRAOfVF649M5RMgWyg8MBaO bkZA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=OgQDdv6G; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id a6-20020a1709064a4600b009a0f9f9d779si13425361ejv.436.2023.09.27.03.47.24 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Sep 2023 03:47:25 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=OgQDdv6G; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 17E253861827 for ; Wed, 27 Sep 2023 10:47:18 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id C21753858436 for ; Wed, 27 Sep 2023 10:46:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C21753858436 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1695811612; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references; bh=DPNS4O8oQeFbOG6/bRzs1jLgyhDNR5m27riFTjVY+uw=; b=OgQDdv6Gn9qITwEOt5FUbJfxvfc8oNa/4u10iP6MylYY3gKXnTNXeKSOH9eAbvunUA+qTn wkBoAvY55KKVJsqITlk/O2Dw1iJ16OF/zGkyJdBywMi0v/ZeMmY3z7aP9N2sDMRzSemsq0 L4Y5nO7HT+QgjovJJuibcU5FiOjLdFM= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-161-sGNx0FOmObOb9EFZTDvSLg-1; Wed, 27 Sep 2023 06:46:48 -0400 X-MC-Unique: sGNx0FOmObOb9EFZTDvSLg-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 622BF1C0CCBC; Wed, 27 Sep 2023 10:46:48 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.193.202]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E858440C2064; Wed, 27 Sep 2023 10:46:47 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 38RAkicQ163448 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 27 Sep 2023 12:46:45 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 38RAkhL2163447; Wed, 27 Sep 2023 12:46:43 +0200 Date: Wed, 27 Sep 2023 12:46:43 +0200 From: Jakub Jelinek To: Richard Biener , Jonathan Wakely , Richard Sandiford Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] vec.h, v2: Make some ops work with non-trivially copy constructible and/or destructible types Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.1 on 10.11.54.1 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP, WEIRD_PORT autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1778187391506021011 X-GMAIL-MSGID: 1778187391506021011 On Wed, Sep 27, 2023 at 07:17:22AM +0000, Richard Biener wrote: > OK I guess. Can you summarize the limitations for non-POD types > in the big comment at the start of vec.h? Still haven't done that, but will do after we flesh out the details below. > (can we put in static_asserts > in the places that obviously do not work?) I've tried to do this though, I think the static_asserts will allow making sure we only use what is supportable and will serve better than any kind of comment. But, I've run into quite a few triggered assertion failures with that, and the question is what we want to do with them. Applying Jakub --- gcc/vec.h.jj 2023-09-27 12:11:56.000000000 +0200 +++ gcc/vec.h 2023-09-27 12:39:50.971613964 +0200 @@ -1160,7 +1160,7 @@ template inline void vec::qsort (int (*cmp) (const void *, const void *)) { - static_assert (std::is_trivially_copyable ::value, ""); +// static_assert (std::is_trivially_copyable ::value, ""); if (length () > 1) gcc_qsort (address (), length (), sizeof (T), cmp); } @@ -1359,7 +1359,7 @@ inline void vec::quick_grow (unsigned len) { gcc_checking_assert (length () <= len && len <= m_vecpfx.m_alloc); - static_assert (std::is_trivially_default_constructible ::value, ""); +// static_assert (std::is_trivially_default_constructible ::value, ""); m_vecpfx.m_num = len; } incremental patch makes stuff work (at lest make in gcc subdir for x86_64-linux with --enable-languages=c,c++,fortran,lto succeeds), so it is just those 2 asserts. Following is full list of failures and discusses details. dbgcnt.cc:132 limits[index].qsort (cmp_tuples); T = std::pair where std::pair is not trivially copyable. Our qsort implementation uses memcpys/memmoves to reshuffle the array elements (as it isn't inlined and so can't use std::swap and the like), so I think we need the types trivially copyable (or at least trivially copy assignable from the same type or something similar if we close all eyes). Is there some std::pair alternative which is trivially copyable, or do we need to define structures to achieve that? Or just close all eyes and allow qsort/sort/stablesort either on trivially copyable types, or on std::pair where both template parameters are trivially copyable? genrecog.cc:3466 candidates.qsort (subroutine_candidate_cmp); T = std::pair ditto dwarf2asm.cc:1061 temp.qsort (compare_strings); T = std::pair ditto tree-ssa-dce.cc:1776 args.qsort (sort_phi_args); T = std::pair ditto tree-ssa-loop-manip.cc:376 names.qsort (loop_name_cmp); T = std::pair ditto omp-oacc-neuter-broadcast.cc:1730 priority.qsort (sort_size_descending); T = std::pair ditto ipa-icf.cc:3087 to_split.qsort (sort_congruence_split); T = std::pair ditto ipa-icf.cc:3360 classes.qsort (sort_congruence_class_groups_by_decl_uid); T = std::pair ditto tree-vect-slp.cc:6991 li_scalar_costs.qsort (li_cost_vec_cmp); T = std::pair ditto tree-vect-slp.cc:7249 lane_defs.qsort (vld_cmp); T = std::pair ditto cfganal.cc:471 control_dependence_map.quick_grow (last_basic_block_for_fn (cfun)); T = bitmap_head This is a different case, bitmap_head has a non-trivial default constructor that essentially fills it with zeros, and for quick_grow we have quick_grow_cleared which default constructs elements, but quick_grow leaves them unconstructed/uninitialized, which is why I wanted to add an assert there, e.g. quick_grow on the wide_int/widest_int WIP would break stuff terribly. In the cfganal.cc case, we call bitmap_initialize on it after growing it, which overwrites all elements and doesn't depend on values of any, so grow_cleared actually is invalid from strict C++ POV, but not in reality. Do we still want the assert in and slow cfganal.cc slightly by using quick_grow_cleared? Or another option would be to make quick_grow work transparently the same as quick_grow_cleared for non-trivially default constructible types. Though, I think it might be better if people explicitly see that the operation is more expensive. tree-ssa-loop-im.cc:2592 first_edge_seq.safe_grow (fes_length + extra_refs.length ()); T = seq_entry Here, seq_entry is: struct seq_entry { seq_entry () {} seq_entry (unsigned f, sm_kind k, tree fr = NULL) : first (f), second (k), from (fr) {} unsigned first; sm_kind second; tree from; }; Wonder if making seq_entry () = default; wouldn't cure this. tree-ssa-loop-im.cc:3499 memory_accesses.refs_loaded_in_loop.quick_grow (number_of_loops (cfun)); T = bitmap_head like the cfganal.cc case. tree-ssa-live.cc:1364 active.quick_grow (last_basic_block_for_fn (fn)); T = bitmap_head ditto rtl-ssa/blocks.cc:60 bb_phis.quick_grow (num_bb_indices); T = rtl_ssa::function_info::bb_phi_info This structure contains bitmap_head, so again isn't default constructible. rtl-ssa/blocks.cc:617 frontiers.safe_grow (num_bb_indices); T = bitmap_head see above tree-vect-data-refs.cc:5369 sel.quick_grow (nelt); T = poly_int<1, long int> Should this use poly_int_pod<1, long int> instead? Or quick_grow_cleared? tree-vect-patterns.cc:2947 unprom.quick_grow (nops); T = vect_unpromoted_value Go for quick_grow_cleared? Something else? tree-ssa-sccvn.cc:5562 accesses.quick_grow (accesses.length () + 1); T = ao_ref This isn't trivially copyable because of 3 poly_int64 members I believe. Shall those be poly_int64_pod? tree-vect-stmts.cc:2811 sel.quick_grow (count); T = poly_int<1, long int> see above ipa-fnsummary.cc:683 avals->m_known_value_ranges.safe_grow (count, true); T = Value_Range Go for cleared? tree-vect-slp.cc:8344 mask.quick_grow (count); T = poly_int<1, long int> see above tree-vect-loop.cc:9042 sel.quick_grow (6); T = poly_int<1, long int> see above config/i386/sse.md:16172 sel.quick_grow (8); T = poly_int<1, long int> see above 2023-09-27 Jakub Jelinek * vec.h (vec_destruct): New function template. (release): Use it for non-trivially destructible T. (truncate): Likewise. (quick_push): Perform a placement new into slot instead of assignment. (pop): For non-trivially destructible T return void rather than T & and destruct the popped element. (quick_insert, ordered_remove): Note that they aren't suitable for non-trivially copyable types. Add static_asserts for that. (block_remove, qsort, sort, stablesort): Assert T is trivially copyable. (quick_grow): Assert T is trivially default constructible. (quick_grow_cleared): Don't call quick_grow, instead inline it by hand except for the new static_assert. (gt_ggc_mx): Assert T is trivially destructable. (auto_vec::operator=): Formatting fixes. (auto_vec::auto_vec): Likewise. (vec_safe_grow_cleared): Don't call vec_safe_grow, instead inline it manually and call quick_grow_cleared method rather than quick_grow. (safe_grow_cleared): Likewise. * edit-context.cc (class line_event): Move definition earlier. --- gcc/vec.h.jj 2023-09-27 10:38:50.635845540 +0200 +++ gcc/vec.h 2023-09-27 12:11:56.665586490 +0200 @@ -185,6 +185,16 @@ extern void dump_vec_loc_statistics (voi /* Hashtable mapping vec addresses to descriptors. */ extern htab_t vec_mem_usage_hash; +/* Destruct N elements in DST. */ + +template +inline void +vec_destruct (T *dst, unsigned n) +{ + for ( ; n; ++dst, --n) + dst->~T (); +} + /* Control data for vectors. This contains the number of allocated and used slots inside a vector. */ @@ -310,6 +320,9 @@ va_heap::release (vec::value) + vec_destruct (v->address (), v->length ()); + if (GATHER_STATISTICS) v->m_vecpfx.release_overhead (v, elt_size * v->allocated (), v->allocated (), true); @@ -588,7 +601,10 @@ public: void splice (const vec &); void splice (const vec *src); T *quick_push (const T &); - T &pop (void); + using pop_ret_type + = typename std::conditional ::value, + T &, void>::type; + pop_ret_type pop (void); void truncate (unsigned); void quick_insert (unsigned, const T &); void ordered_remove (unsigned); @@ -735,8 +751,9 @@ vec_safe_grow_cleared (vecaddress () + oldlen, len - oldlen); + gcc_checking_assert (len >= oldlen); + vec_safe_reserve (v, len - oldlen, exact PASS_MEM_STAT); + v->quick_grow_cleared (len); } @@ -1005,19 +1022,24 @@ vec::quick_push (const T { gcc_checking_assert (space (1)); T *slot = &address ()[m_vecpfx.m_num++]; - *slot = obj; + ::new (static_cast(slot)) T (obj); return slot; } -/* Pop and return the last element off the end of the vector. */ +/* Pop and return a reference to the last element off the end of the + vector. If T has non-trivial destructor, this method just pops + the element and returns void type. */ template -inline T & +inline typename vec::pop_ret_type vec::pop (void) { gcc_checking_assert (length () > 0); - return address ()[--m_vecpfx.m_num]; + T &last = address ()[--m_vecpfx.m_num]; + if (!std::is_trivially_destructible ::value) + last.~T (); + return static_cast (last); } @@ -1028,13 +1050,17 @@ template inline void vec::truncate (unsigned size) { - gcc_checking_assert (length () >= size); + unsigned l = length (); + gcc_checking_assert (l >= size); + if (!std::is_trivially_destructible ::value) + vec_destruct (address () + l, l - size); m_vecpfx.m_num = size; } /* Insert an element, OBJ, at the IXth position of this vector. There - must be sufficient space. */ + must be sufficient space. This operation is not suitable for non-trivially + copyable types. */ template inline void @@ -1042,6 +1068,7 @@ vec::quick_insert (unsig { gcc_checking_assert (length () < allocated ()); gcc_checking_assert (ix <= length ()); + static_assert (std::is_trivially_copyable ::value, ""); T *slot = &address ()[ix]; memmove (slot + 1, slot, (m_vecpfx.m_num++ - ix) * sizeof (T)); *slot = obj; @@ -1050,13 +1077,14 @@ vec::quick_insert (unsig /* Remove an element from the IXth position of this vector. Ordering of remaining elements is preserved. This is an O(N) operation due to - memmove. */ + memmove. Not suitable for non-trivially copyable types. */ template inline void vec::ordered_remove (unsigned ix) { gcc_checking_assert (ix < length ()); + static_assert (std::is_trivially_copyable ::value, ""); T *slot = &address ()[ix]; memmove (slot, slot + 1, (--m_vecpfx.m_num - ix) * sizeof (T)); } @@ -1104,6 +1132,7 @@ inline void vec::unordered_remove (unsigned ix) { gcc_checking_assert (ix < length ()); + static_assert (std::is_trivially_copyable ::value, ""); T *p = address (); p[ix] = p[--m_vecpfx.m_num]; } @@ -1117,6 +1146,7 @@ inline void vec::block_remove (unsigned ix, unsigned len) { gcc_checking_assert (ix + len <= length ()); + static_assert (std::is_trivially_copyable ::value, ""); T *slot = &address ()[ix]; m_vecpfx.m_num -= len; memmove (slot, slot + len, (m_vecpfx.m_num - ix) * sizeof (T)); @@ -1130,6 +1160,7 @@ template inline void vec::qsort (int (*cmp) (const void *, const void *)) { + static_assert (std::is_trivially_copyable ::value, ""); if (length () > 1) gcc_qsort (address (), length (), sizeof (T), cmp); } @@ -1142,6 +1173,7 @@ inline void vec::sort (int (*cmp) (const void *, const void *, void *), void *data) { + static_assert (std::is_trivially_copyable ::value, ""); if (length () > 1) gcc_sort_r (address (), length (), sizeof (T), cmp, data); } @@ -1154,6 +1186,7 @@ inline void vec::stablesort (int (*cmp) (const void *, const void *, void *), void *data) { + static_assert (std::is_trivially_copyable ::value, ""); if (length () > 1) gcc_stablesort_r (address (), length (), sizeof (T), cmp, data); } @@ -1326,6 +1359,7 @@ inline void vec::quick_grow (unsigned len) { gcc_checking_assert (length () <= len && len <= m_vecpfx.m_alloc); + static_assert (std::is_trivially_default_constructible ::value, ""); m_vecpfx.m_num = len; } @@ -1339,7 +1373,8 @@ vec::quick_grow_cleared { unsigned oldlen = length (); size_t growby = len - oldlen; - quick_grow (len); + gcc_checking_assert (length () <= len && len <= m_vecpfx.m_alloc); + m_vecpfx.m_num = len; if (growby != 0) vec_default_construct (address () + oldlen, growby); } @@ -1350,6 +1385,7 @@ template void gt_ggc_mx (vec *v) { + static_assert (std::is_trivially_destructible ::value, ""); extern void gt_ggc_mx (T &); for (unsigned i = 0; i < v->length (); i++) gt_ggc_mx ((*v)[i]); @@ -1359,6 +1395,7 @@ template void gt_ggc_mx (vec *v ATTRIBUTE_UNUSED) { + static_assert (std::is_trivially_destructible ::value, ""); /* Nothing to do. Vectors of atomic types wrt GC do not need to be traversed. */ } @@ -1518,7 +1555,10 @@ public: void safe_splice (const vec & CXX_MEM_STAT_INFO); T *quick_push (const T &); T *safe_push (const T &CXX_MEM_STAT_INFO); - T &pop (void); + using pop_ret_type + = typename std::conditional ::value, + T &, void>::type; + pop_ret_type pop (void); void truncate (unsigned); void safe_grow (unsigned, bool = false CXX_MEM_STAT_INFO); void safe_grow_cleared (unsigned, bool = false CXX_MEM_STAT_INFO); @@ -1627,8 +1667,8 @@ public: auto_vec& operator= (vec&& r) { - if (this == &r) - return *this; + if (this == &r) + return *this; gcc_assert (!r.using_auto_storage ()); this->release (); @@ -1639,8 +1679,8 @@ public: auto_vec& operator= (auto_vec &&r) { - if (this == &r) - return *this; + if (this == &r) + return *this; gcc_assert (!r.using_auto_storage ()); this->release (); @@ -1660,7 +1700,7 @@ public: // You probably don't want to copy a vector, so these are deleted to prevent // unintentional use. If you really need a copy of the vectors contents you // can use copy (). - auto_vec(const auto_vec &) = delete; + auto_vec (const auto_vec &) = delete; auto_vec &operator= (const auto_vec &) = delete; }; @@ -1986,10 +2026,12 @@ vec::safe_push (cons } -/* Pop and return the last element off the end of the vector. */ +/* Pop and return a reference to the last element off the end of the + vector. If T has non-trivial destructor, this method just pops + last element and returns void. */ template -inline T & +inline typename vec::pop_ret_type vec::pop (void) { return m_vec->pop (); @@ -2038,10 +2080,12 @@ vec::safe_grow_clear MEM_STAT_DECL) { unsigned oldlen = length (); - size_t growby = len - oldlen; - safe_grow (len, exact PASS_MEM_STAT); - if (growby != 0) - vec_default_construct (address () + oldlen, growby); + gcc_checking_assert (oldlen <= len); + reserve (len - oldlen, exact PASS_MEM_STAT); + if (m_vec) + m_vec->quick_grow_cleared (len); + else + gcc_checking_assert (len == 0); } --- gcc/edit-context.cc.jj 2023-09-27 10:37:38.600848724 +0200 +++ gcc/edit-context.cc 2023-09-27 10:40:04.834812220 +0200 @@ -122,6 +122,32 @@ class added_line int m_len; }; +/* Class for representing edit events that have occurred on one line of + one file: the replacement of some text betweeen some columns + on the line. + + Subsequent events will need their columns adjusting if they're + are on this line and their column is >= the start point. */ + +class line_event +{ + public: + line_event (int start, int next, int len) : m_start (start), + m_delta (len - (next - start)) {} + + int get_effective_column (int orig_column) const + { + if (orig_column >= m_start) + return orig_column += m_delta; + else + return orig_column; + } + + private: + int m_start; + int m_delta; +}; + /* The state of one edited line within an edited_file. As well as the current content of the line, it contains a record of the changes, so that further changes can be applied in the correct @@ -172,32 +198,6 @@ class edited_line auto_vec m_predecessors; }; -/* Class for representing edit events that have occurred on one line of - one file: the replacement of some text betweeen some columns - on the line. - - Subsequent events will need their columns adjusting if they're - are on this line and their column is >= the start point. */ - -class line_event -{ - public: - line_event (int start, int next, int len) : m_start (start), - m_delta (len - (next - start)) {} - - int get_effective_column (int orig_column) const - { - if (orig_column >= m_start) - return orig_column += m_delta; - else - return orig_column; - } - - private: - int m_start; - int m_delta; -}; - /* Forward decls. */ static void