From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 A90503858C74 for ; Wed, 27 Sep 2023 05:03:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A90503858C74 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=1695791016; 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; bh=4p7BfR7BPnnlvoP2sA4mgRUYJ42Ga+DwwNxI/V4LcO8=; b=U1B5pdRXWYC3F66Jcch9Ws8vv+vVf1+lCI4Iib+UMM9ftsnr9rOestbonTD+/jlBDuHbys QEWi7PEaIP1xp+R0MOgFtTQhHCsIH2o5wVul3s+dnNdeXHg1vzRNNtrk6XArXotg5LLLJD V8G+O+Xzi5gfJ1a8ooNhy+mLZOKn2Gs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-517-aRczpHuOMcOshpyYuQPKkQ-1; Wed, 27 Sep 2023 01:03:34 -0400 X-MC-Unique: aRczpHuOMcOshpyYuQPKkQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (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 2B3B98002B2; Wed, 27 Sep 2023 05:03:34 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.193.202]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2A0E514171B6; Wed, 27 Sep 2023 05:03:33 +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 38R53UGa140354 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 27 Sep 2023 07:03:30 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 38R53TCK140353; Wed, 27 Sep 2023 07:03:29 +0200 Date: Wed, 27 Sep 2023 07:03:29 +0200 From: Jakub Jelinek To: Richard Biener Cc: gcc-patches@gcc.gnu.org, Jonathan Wakely Subject: [PATCH] vec.h: Make some ops work with non-trivially copy constructible and/or destructible types Message-ID: Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-3.4 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,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hi! We have some very limited support for non-POD types in vec.h (in particular grow_cleared will invoke default ctors on the cleared elements and vector copying invokes copy ctors. My pending work on wide_int/widest_int which makes those two non-trivially default/copy constructible, assignable and destructible shows this isn't enough though. In particular the uses of it in irange shows that quick_push still uses just assignment operator rather than copy construction and we never invoke destructors on anything. The following patch does that for quick_push (copy construction using placement new rather than assignment, for trivially copy constructible types I think it should be the same) and invokes destructors (only if non-trivially destructible) in pop, release and truncate. Now as discussed last night on IRC, the pop case is problematic, because our pop actually does two things, it decreases length (so the previous last element should be destructed) but also returns a reference to it. We have some 300+ uses of this and the reference rather than returning it by value is useful at least for the elements which are (larger) POD structures, so I'm not prepared to change that. Though obviously for types with non-trivial destructors returning a reference to just destructed element is not a good idea. So, this patch for that case only makes pop return void instead and any users wishing to get the last element need to use last () and pop () separately (currently there are none). Note, a lot of vec.h operations is still not friendly for non-POD types, I've added a comment for quick_insert and ordered_remove, but qsort is such a case as well and in fact most others too. For non-POD, I'd say with this patch it is safe just to {quick,safe}_grow_cleared (but not just *_grow), {quick,safe}_push, pop, truncate, release, copy them around and ops which do not add/remove any elements or move them around. And obviously using non-trivially destructible types in va_gc vectors is undesirable as well. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 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. (quick_insert, ordered_remove): Note that they aren't suitable for non-PODs. (pop): For non-trivially destructible T return void rather than T & and destruct the popped element. * edit-context.cc (class line_event): Move definition earlier. --- gcc/vec.h.jj 2023-09-26 16:44:30.637902359 +0200 +++ gcc/vec.h 2023-09-26 21:17:30.366534474 +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); @@ -1005,19 +1021,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 +1049,16 @@ 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-PODs. */ template inline void @@ -1050,7 +1074,7 @@ 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-PODs. */ template inline void @@ -1518,7 +1542,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); @@ -1986,10 +2013,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 (); --- gcc/edit-context.cc.jj 2023-01-02 09:32:43.106985882 +0100 +++ gcc/edit-context.cc 2023-09-26 19:39:20.213374419 +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 Jakub