public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] define auto_vec copy ctor and assignment (PR 90904)
@ 2021-04-26 23:30 Martin Sebor
  2021-04-27  7:58 ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-04-26 23:30 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 586 bytes --]

PR 90904 notes that auto_vec is unsafe to copy and assign because
the class manages its own memory but doesn't define (or delete)
either special function.  Since I first ran into the problem,
auto_vec has grown a move ctor and move assignment from
a dynamically-allocated vec but still no copy ctor or copy
assignment operator.

The attached patch adds the two special functions to auto_vec along
with a few simple tests.  It makes auto_vec safe to use in containers
that expect copyable and assignable element types and passes bootstrap
and regression testing on x86_64-linux.

Martin

[-- Attachment #2: gcc-90904.diff --]
[-- Type: text/x-patch, Size: 4081 bytes --]

PR middle-end/90904 - vec assignment and copying undefined

gcc/ChangeLog:

	* vec.c (test_copy_assign): New function.
	(vec_c_tests): Call it.
	* vec.h (auto_vec copy ctor): Define.
	(auto_vec::operator=): Define.

diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..c9299875257 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -317,6 +317,83 @@ test_safe_push ()
   ASSERT_EQ (7, v[2]);
 }
 
+/* Verify that auto_vec copy ctor and assignment work correctly.  */
+
+static void
+test_copy_assign ()
+{
+  auto_vec <int> a0;
+  auto_vec <int> b0 (0);
+  auto_vec <int> c0 (7);
+  ASSERT_EQ (0, b0.length ());
+  ASSERT_EQ (0, c0.length ());
+
+  a0 = a0;
+  ASSERT_EQ (0, a0.length ());
+  b0 = a0;
+  ASSERT_EQ (0, b0.length ());
+  c0 = a0;
+  ASSERT_EQ (0, c0.length ());
+
+  auto_vec <int> a3;
+  a3.safe_push (5);
+  a3.safe_push (6);
+  a3.safe_push (7);
+
+  auto_vec <int> b3 (a3);
+  ASSERT_EQ (3, b3.length ());
+  ASSERT_EQ (5, b3[0]);
+  ASSERT_EQ (6, b3[1]);
+  ASSERT_EQ (7, b3[2]);
+
+  auto_vec <int> c3;
+  c3 = b3;
+  ASSERT_EQ (3, c3.length ());
+  ASSERT_EQ (5, c3[0]);
+  ASSERT_EQ (6, c3[1]);
+  ASSERT_EQ (7, c3[2]);
+
+  auto_vec <int> d4;
+  d4.safe_push (1);
+  d4.safe_push (2);
+  d4.safe_push (3);
+  d4.safe_push (4);
+
+  c3 = d4;
+  ASSERT_EQ (4, c3.length ());
+  ASSERT_EQ (1, c3[0]);
+  ASSERT_EQ (2, c3[1]);
+  ASSERT_EQ (3, c3[2]);
+  ASSERT_EQ (4, c3[3]);
+
+  d4 = a3;
+  ASSERT_EQ (3, d4.length ());
+  ASSERT_EQ (5, d4[0]);
+  ASSERT_EQ (6, d4[1]);
+  ASSERT_EQ (7, d4[2]);
+
+  a3 = b0;
+  ASSERT_EQ (0, a3.length ());
+
+  b3 = b0;
+  ASSERT_EQ (0, b3.length ());
+
+  c3 = c0;
+  ASSERT_EQ (0, c3.length ());
+
+  b0 = d4;
+  ASSERT_EQ (3, b0.length ());
+  ASSERT_EQ (5, b0[0]);
+  ASSERT_EQ (6, b0[1]);
+  ASSERT_EQ (7, b0[2]);
+
+  c0 = d4;
+  ASSERT_EQ (3, c0.length ());
+  ASSERT_EQ (5, c0[0]);
+  ASSERT_EQ (6, c0[1]);
+  ASSERT_EQ (7, c0[2]);
+}
+
 /* Verify that vec::truncate works correctly.  */
 
 static void
@@ -549,6 +626,7 @@ vec_c_tests ()
 {
   test_quick_push ();
   test_safe_push ();
+  test_copy_assign ();
   test_truncate ();
   test_safe_grow_cleared ();
   test_pop ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 24df2db0eeb..61397bb7ee0 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1551,12 +1551,21 @@ public:
   auto_vec (size_t n CXX_MEM_STAT_INFO) { this->create (n PASS_MEM_STAT); }
   ~auto_vec () { this->release (); }
 
+  /* Copy ctor.  */
+  auto_vec (const auto_vec&);
+
+  /* Move ctor from a heap-allocated vec.  */
   auto_vec (vec<T, va_heap>&& r)
     {
       gcc_assert (!r.using_auto_storage ());
       this->m_vec = r.m_vec;
       r.m_vec = NULL;
     }
+
+  /* Copy asssignment.  */
+  auto_vec& operator= (const auto_vec&);
+
+  /* Move asssignment from a heap-allocated vec.  */
   auto_vec& operator= (vec<T, va_heap>&& r)
     {
       gcc_assert (!r.using_auto_storage ());
@@ -1567,6 +1576,49 @@ public:
     }
 };
 
+/* Copy elements from R to *THIS.  */
+
+template<typename T>
+auto_vec<T, 0>::auto_vec (const auto_vec& r)
+{
+  const unsigned n = r.length ();
+  this->create (n);
+  if (n)
+    {
+      vec_copy_construct (this->address (), r.address (), n);
+      this->m_vec->m_vecpfx.m_num = n;
+    }
+}
+
+/* Assign elements from R over *THIS, invoking the copy assignment
+   operator on the initial elements and the copy ctor on the excess.  */
+
+template<typename T>
+auto_vec<T, 0>& auto_vec<T, 0>::operator= (const auto_vec& r)
+{
+  unsigned n0 = this->length ();
+  const unsigned n1 = r.length ();
+  if (n0 < n1)
+    this->safe_grow (n1);
+  else
+    {
+      this->truncate (n1);
+      n0 = n1;
+    }
+
+  T *dst = this->address ();
+  const T *src = r.address ();
+
+  /* Copy-assign over the first N0 elements.  */
+  for (unsigned i = 0; i != n0; ++i)
+    dst[i] = src[i];
+
+  if (n0 < n1)
+    /* Copy-construct elements in excess of N0.  */
+    vec_copy_construct (dst + n0, src + n0, n1 - n0);
+
+  return *this;
+}
 
 /* Allocate heap memory for pointer V and create the internal vector
    with space for NELEMS elements.  If NELEMS is 0, the internal

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-04-26 23:30 [PATCH] define auto_vec copy ctor and assignment (PR 90904) Martin Sebor
@ 2021-04-27  7:58 ` Richard Biener
  2021-04-27 13:58   ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-04-27  7:58 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> PR 90904 notes that auto_vec is unsafe to copy and assign because
> the class manages its own memory but doesn't define (or delete)
> either special function.  Since I first ran into the problem,
> auto_vec has grown a move ctor and move assignment from
> a dynamically-allocated vec but still no copy ctor or copy
> assignment operator.
>
> The attached patch adds the two special functions to auto_vec along
> with a few simple tests.  It makes auto_vec safe to use in containers
> that expect copyable and assignable element types and passes bootstrap
> and regression testing on x86_64-linux.

The question is whether we want such uses to appear since those
can be quite inefficient?  Thus the option is to delete those operators?

Richard.

> Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-04-27  7:58 ` Richard Biener
@ 2021-04-27 13:58   ` Martin Sebor
  2021-04-27 14:04     ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-04-27 13:58 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On 4/27/21 1:58 AM, Richard Biener wrote:
> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>> the class manages its own memory but doesn't define (or delete)
>> either special function.  Since I first ran into the problem,
>> auto_vec has grown a move ctor and move assignment from
>> a dynamically-allocated vec but still no copy ctor or copy
>> assignment operator.
>>
>> The attached patch adds the two special functions to auto_vec along
>> with a few simple tests.  It makes auto_vec safe to use in containers
>> that expect copyable and assignable element types and passes bootstrap
>> and regression testing on x86_64-linux.
> 
> The question is whether we want such uses to appear since those
> can be quite inefficient?  Thus the option is to delete those operators?

I would strongly prefer the generic vector class to have the properties
expected of any other generic container: copyable and assignable.  If
we also want another vector type with this restriction I suggest to add
another "noncopyable" type and make that property explicit in its name.
I can submit one in a followup patch if you think we need one.

Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-04-27 13:58   ` Martin Sebor
@ 2021-04-27 14:04     ` Richard Biener
  2021-04-27 15:52       ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-04-27 14:04 UTC (permalink / raw)
  To: Martin Sebor; +Cc: gcc-patches

On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 4/27/21 1:58 AM, Richard Biener wrote:
> > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> >>
> >> PR 90904 notes that auto_vec is unsafe to copy and assign because
> >> the class manages its own memory but doesn't define (or delete)
> >> either special function.  Since I first ran into the problem,
> >> auto_vec has grown a move ctor and move assignment from
> >> a dynamically-allocated vec but still no copy ctor or copy
> >> assignment operator.
> >>
> >> The attached patch adds the two special functions to auto_vec along
> >> with a few simple tests.  It makes auto_vec safe to use in containers
> >> that expect copyable and assignable element types and passes bootstrap
> >> and regression testing on x86_64-linux.
> >
> > The question is whether we want such uses to appear since those
> > can be quite inefficient?  Thus the option is to delete those operators?
>
> I would strongly prefer the generic vector class to have the properties
> expected of any other generic container: copyable and assignable.  If
> we also want another vector type with this restriction I suggest to add
> another "noncopyable" type and make that property explicit in its name.
> I can submit one in a followup patch if you think we need one.

I'm not sure (and not strictly against the copy and assign).  Looking around
I see that vec<> does not do deep copying.  Making auto_vec<> do it
might be surprising (I added the move capability to match how vec<>
is used - as "reference" to a vector)

Richard.

> Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-04-27 14:04     ` Richard Biener
@ 2021-04-27 15:52       ` Martin Sebor
  2021-05-03 21:50         ` [PING][PATCH] " Martin Sebor
  2021-05-27 20:53         ` [PATCH] " Jason Merrill
  0 siblings, 2 replies; 59+ messages in thread
From: Martin Sebor @ 2021-04-27 15:52 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2398 bytes --]

On 4/27/21 8:04 AM, Richard Biener wrote:
> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>
>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>> the class manages its own memory but doesn't define (or delete)
>>>> either special function.  Since I first ran into the problem,
>>>> auto_vec has grown a move ctor and move assignment from
>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>> assignment operator.
>>>>
>>>> The attached patch adds the two special functions to auto_vec along
>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>> that expect copyable and assignable element types and passes bootstrap
>>>> and regression testing on x86_64-linux.
>>>
>>> The question is whether we want such uses to appear since those
>>> can be quite inefficient?  Thus the option is to delete those operators?
>>
>> I would strongly prefer the generic vector class to have the properties
>> expected of any other generic container: copyable and assignable.  If
>> we also want another vector type with this restriction I suggest to add
>> another "noncopyable" type and make that property explicit in its name.
>> I can submit one in a followup patch if you think we need one.
> 
> I'm not sure (and not strictly against the copy and assign).  Looking around
> I see that vec<> does not do deep copying.  Making auto_vec<> do it
> might be surprising (I added the move capability to match how vec<>
> is used - as "reference" to a vector)

The vec base classes are special: they have no ctors at all (because
of their use in unions).  That's something we might have to live with
but it's not a model to follow in ordinary containers.

The auto_vec class was introduced to fill the need for a conventional
sequence container with a ctor and dtor.  The missing copy ctor and
assignment operators were an oversight, not a deliberate feature.
This change fixes that oversight.

The revised patch also adds a copy ctor/assignment to the auto_vec
primary template (that's also missing it).  In addition, it adds
a new class called auto_vec_ncopy that disables copying and
assignment as you prefer.  It also disables copying for
the auto_string_vec class.

Martin

[-- Attachment #2: gcc-90904.diff --]
[-- Type: text/x-patch, Size: 6204 bytes --]

PR middle-end/90904 - vec assignment and copying undefined

gcc/ChangeLog:

	PR middle-end/90904
	* vec.c (test_copy_assign): New function.
	(vec_c_tests): Call it.
	* vec.h (vec_assign): New function.
	(auto_vec copy ctor): Define.
	(auto_vec::operator=): Define.
	(auto_vec_no_copy): New class template.
	(auto_string_vec): Disable copying/assignment.

diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..f15530d1e43 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -317,6 +317,86 @@ test_safe_push ()
   ASSERT_EQ (7, v[2]);
 }
 
+
+/* Verify that auto_vec copy ctor and assignment work correctly.  */
+
+template <size_t N>
+void test_copy_assign ()
+{
+  typedef auto_vec <int, N> test_vec;
+
+  test_vec a0;
+  test_vec b0 (0);
+  test_vec c0 (7);
+  ASSERT_EQ (0, b0.length ());
+  ASSERT_EQ (0, c0.length ());
+
+  a0 = a0;
+  ASSERT_EQ (0, a0.length ());
+  b0 = a0;
+  ASSERT_EQ (0, b0.length ());
+  c0 = a0;
+  ASSERT_EQ (0, c0.length ());
+
+  test_vec a3;
+  a3.safe_push (5);
+  a3.safe_push (6);
+  a3.safe_push (7);
+
+  test_vec b3 (a3);
+  ASSERT_EQ (3, b3.length ());
+  ASSERT_EQ (5, b3[0]);
+  ASSERT_EQ (6, b3[1]);
+  ASSERT_EQ (7, b3[2]);
+
+  test_vec c3;
+  c3 = b3;
+  ASSERT_EQ (3, c3.length ());
+  ASSERT_EQ (5, c3[0]);
+  ASSERT_EQ (6, c3[1]);
+  ASSERT_EQ (7, c3[2]);
+
+  test_vec d4;
+  d4.safe_push (1);
+  d4.safe_push (2);
+  d4.safe_push (3);
+  d4.safe_push (4);
+
+  c3 = d4;
+  ASSERT_EQ (4, c3.length ());
+  ASSERT_EQ (1, c3[0]);
+  ASSERT_EQ (2, c3[1]);
+  ASSERT_EQ (3, c3[2]);
+  ASSERT_EQ (4, c3[3]);
+
+  d4 = a3;
+  ASSERT_EQ (3, d4.length ());
+  ASSERT_EQ (5, d4[0]);
+  ASSERT_EQ (6, d4[1]);
+  ASSERT_EQ (7, d4[2]);
+
+  a3 = b0;
+  ASSERT_EQ (0, a3.length ());
+
+  b3 = b0;
+  ASSERT_EQ (0, b3.length ());
+
+  c3 = c0;
+  ASSERT_EQ (0, c3.length ());
+
+  b0 = d4;
+  ASSERT_EQ (3, b0.length ());
+  ASSERT_EQ (5, b0[0]);
+  ASSERT_EQ (6, b0[1]);
+  ASSERT_EQ (7, b0[2]);
+
+  c0 = d4;
+  ASSERT_EQ (3, c0.length ());
+  ASSERT_EQ (5, c0[0]);
+  ASSERT_EQ (6, c0[1]);
+  ASSERT_EQ (7, c0[2]);
+}
+
 /* Verify that vec::truncate works correctly.  */
 
 static void
@@ -549,6 +629,8 @@ vec_c_tests ()
 {
   test_quick_push ();
   test_safe_push ();
+  test_copy_assign<0> ();
+  test_copy_assign<2> ();
   test_truncate ();
   test_safe_grow_cleared ();
   test_pop ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 24df2db0eeb..f5dd5bb329a 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -1509,7 +1509,41 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
+
 template<typename T, size_t N = 0>
+class auto_vec;
+
+/* Safely assign elements from SRC to DST, invoking the copy assignment
+   operator on the initial elements and the copy ctor on the excess.  */
+
+template<typename T, size_t N>
+auto_vec<T, N>& vec_assign (auto_vec<T, N> &dst, const auto_vec<T, N> &src)
+{
+  unsigned n0 = dst.length ();
+  const unsigned n1 = src.length ();
+  if (n0 < n1)
+    dst.safe_grow (n1);
+  else
+    {
+      dst.truncate (n1);
+      n0 = n1;
+    }
+
+  T *pdst = dst.address ();
+  const T *psrc = src.address ();
+
+  /* Copy-assign over the first N0 elements.  */
+  for (unsigned i = 0; i != n0; ++i)
+    pdst[i] = psrc[i];
+
+  if (n0 < n1)
+    /* Copy-construct elements in excess of N0.  */
+    vec_copy_construct (pdst + n0, psrc + n0, n1 - n0);
+
+  return dst;
+}
+
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1536,11 +1570,34 @@ public:
     this->release ();
   }
 
+  /* Copy ctor.  */
+  auto_vec (const auto_vec &);
+
+  /* Copy asssignment.  */
+  auto_vec& operator= (const auto_vec &r)
+  {
+    return vec_assign (*this, r);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
 };
 
+/* Copy elements from R to *THIS.  */
+
+template<typename T, size_t N>
+auto_vec<T, N>::auto_vec (const auto_vec& r)
+{
+  const unsigned n = r.length ();
+  this->create (n);
+  if (n)
+    {
+      vec_copy_construct (this->address (), r.address (), n);
+      this->m_vec->m_vecpfx.m_num = n;
+    }
+}
+
 /* auto_vec is a sub class of vec whose storage is released when it is
   destroyed. */
 template<typename T>
@@ -1551,12 +1608,24 @@ public:
   auto_vec (size_t n CXX_MEM_STAT_INFO) { this->create (n PASS_MEM_STAT); }
   ~auto_vec () { this->release (); }
 
+  /* Copy ctor.  */
+  auto_vec (const auto_vec&);
+
+  /* Move ctor from vec that's not auto_vec.  */
   auto_vec (vec<T, va_heap>&& r)
     {
       gcc_assert (!r.using_auto_storage ());
       this->m_vec = r.m_vec;
       r.m_vec = NULL;
     }
+
+  /* Copy asssignment.  */
+  auto_vec& operator= (const auto_vec &rhs)
+  {
+    return vec_assign (*this, rhs);
+  }
+
+  /* Move asssignment from vec that's not auto_vec.  */
   auto_vec& operator= (vec<T, va_heap>&& r)
     {
       gcc_assert (!r.using_auto_storage ());
@@ -1567,6 +1636,35 @@ public:
     }
 };
 
+/* Copy elements from R to *THIS.  */
+
+template<typename T>
+auto_vec<T, 0>::auto_vec (const auto_vec& r)
+{
+  const unsigned n = r.length ();
+  this->create (n);
+  if (n)
+    {
+      vec_copy_construct (this->address (), r.address (), n);
+      this->m_vec->m_vecpfx.m_num = n;
+    }
+}
+
+/* Same as auto_vec<T, 0> but with deleted copy ctor and assignment
+   operator to detect uses of these special functions in contexts
+   where they may be inefficient.  */
+
+template<typename T>
+class auto_vec_no_copy: public auto_vec<T, 0>
+{
+public:
+  /* Inherit all ctors.  */
+  using auto_vec<T, 0>::auto_vec;
+
+private:
+  /* Prevent copying and assignment.  */
+  DISABLE_COPY_AND_ASSIGN (auto_vec_no_copy);
+};
 
 /* Allocate heap memory for pointer V and create the internal vector
    with space for NELEMS elements.  If NELEMS is 0, the internal
@@ -1587,7 +1685,11 @@ vec_alloc (vec<T> *&v, unsigned nelems CXX_MEM_STAT_INFO)
 class auto_string_vec : public auto_vec <char *>
 {
  public:
+  auto_string_vec (): auto_vec () { }
   ~auto_string_vec ();
+
+private:
+  DISABLE_COPY_AND_ASSIGN (auto_string_vec);
 };
 
 /* A subclass of auto_vec <T *> that deletes all of its elements on

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-04-27 15:52       ` Martin Sebor
@ 2021-05-03 21:50         ` Martin Sebor
  2021-05-11 20:02           ` [PING 2][PATCH] " Martin Sebor
  2021-05-27 20:53         ` [PATCH] " Jason Merrill
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-05-03 21:50 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

Ping:

https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568901.html

On 4/27/21 9:52 AM, Martin Sebor wrote:
> On 4/27/21 8:04 AM, Richard Biener wrote:
>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>
>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>
>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>> the class manages its own memory but doesn't define (or delete)
>>>>> either special function.  Since I first ran into the problem,
>>>>> auto_vec has grown a move ctor and move assignment from
>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>> assignment operator.
>>>>>
>>>>> The attached patch adds the two special functions to auto_vec along
>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>> that expect copyable and assignable element types and passes bootstrap
>>>>> and regression testing on x86_64-linux.
>>>>
>>>> The question is whether we want such uses to appear since those
>>>> can be quite inefficient?  Thus the option is to delete those 
>>>> operators?
>>>
>>> I would strongly prefer the generic vector class to have the properties
>>> expected of any other generic container: copyable and assignable.  If
>>> we also want another vector type with this restriction I suggest to add
>>> another "noncopyable" type and make that property explicit in its name.
>>> I can submit one in a followup patch if you think we need one.
>>
>> I'm not sure (and not strictly against the copy and assign).  Looking 
>> around
>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>> might be surprising (I added the move capability to match how vec<>
>> is used - as "reference" to a vector)
> 
> The vec base classes are special: they have no ctors at all (because
> of their use in unions).  That's something we might have to live with
> but it's not a model to follow in ordinary containers.
> 
> The auto_vec class was introduced to fill the need for a conventional
> sequence container with a ctor and dtor.  The missing copy ctor and
> assignment operators were an oversight, not a deliberate feature.
> This change fixes that oversight.
> 
> The revised patch also adds a copy ctor/assignment to the auto_vec
> primary template (that's also missing it).  In addition, it adds
> a new class called auto_vec_ncopy that disables copying and
> assignment as you prefer.  It also disables copying for
> the auto_string_vec class.
> 
> Martin


^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PING 2][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-05-03 21:50         ` [PING][PATCH] " Martin Sebor
@ 2021-05-11 20:02           ` Martin Sebor
  2021-05-27 19:33             ` [PING 3][PATCH] " Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-05-11 20:02 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

Ping 2:
https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568901.html


On 5/3/21 3:50 PM, Martin Sebor wrote:
> Ping:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568901.html
> 
> On 4/27/21 9:52 AM, Martin Sebor wrote:
>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>
>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>> either special function.  Since I first ran into the problem,
>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>> assignment operator.
>>>>>>
>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>>> that expect copyable and assignable element types and passes 
>>>>>> bootstrap
>>>>>> and regression testing on x86_64-linux.
>>>>>
>>>>> The question is whether we want such uses to appear since those
>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>> operators?
>>>>
>>>> I would strongly prefer the generic vector class to have the properties
>>>> expected of any other generic container: copyable and assignable.  If
>>>> we also want another vector type with this restriction I suggest to add
>>>> another "noncopyable" type and make that property explicit in its name.
>>>> I can submit one in a followup patch if you think we need one.
>>>
>>> I'm not sure (and not strictly against the copy and assign).  Looking 
>>> around
>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>> might be surprising (I added the move capability to match how vec<>
>>> is used - as "reference" to a vector)
>>
>> The vec base classes are special: they have no ctors at all (because
>> of their use in unions).  That's something we might have to live with
>> but it's not a model to follow in ordinary containers.
>>
>> The auto_vec class was introduced to fill the need for a conventional
>> sequence container with a ctor and dtor.  The missing copy ctor and
>> assignment operators were an oversight, not a deliberate feature.
>> This change fixes that oversight.
>>
>> The revised patch also adds a copy ctor/assignment to the auto_vec
>> primary template (that's also missing it).  In addition, it adds
>> a new class called auto_vec_ncopy that disables copying and
>> assignment as you prefer.  It also disables copying for
>> the auto_string_vec class.
>>
>> Martin
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PING 3][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-05-11 20:02           ` [PING 2][PATCH] " Martin Sebor
@ 2021-05-27 19:33             ` Martin Sebor
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Sebor @ 2021-05-27 19:33 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Richard Biener, gcc-patches

Jason, I wonder if you could review this patch that Richard has
apparently decided to defer to others.

https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568901.html

Thanks

On 5/11/21 2:02 PM, Martin Sebor wrote:
> Ping 2:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568901.html
> 
> 
> On 5/3/21 3:50 PM, Martin Sebor wrote:
>> Ping:
>>
>> https://gcc.gnu.org/pipermail/gcc-patches/2021-April/568901.html
>>
>> On 4/27/21 9:52 AM, Martin Sebor wrote:
>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>
>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>
>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>> assignment operator.
>>>>>>>
>>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>>> with a few simple tests.  It makes auto_vec safe to use in 
>>>>>>> containers
>>>>>>> that expect copyable and assignable element types and passes 
>>>>>>> bootstrap
>>>>>>> and regression testing on x86_64-linux.
>>>>>>
>>>>>> The question is whether we want such uses to appear since those
>>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>>> operators?
>>>>>
>>>>> I would strongly prefer the generic vector class to have the 
>>>>> properties
>>>>> expected of any other generic container: copyable and assignable.  If
>>>>> we also want another vector type with this restriction I suggest to 
>>>>> add
>>>>> another "noncopyable" type and make that property explicit in its 
>>>>> name.
>>>>> I can submit one in a followup patch if you think we need one.
>>>>
>>>> I'm not sure (and not strictly against the copy and assign).  
>>>> Looking around
>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>> might be surprising (I added the move capability to match how vec<>
>>>> is used - as "reference" to a vector)
>>>
>>> The vec base classes are special: they have no ctors at all (because
>>> of their use in unions).  That's something we might have to live with
>>> but it's not a model to follow in ordinary containers.
>>>
>>> The auto_vec class was introduced to fill the need for a conventional
>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>> assignment operators were an oversight, not a deliberate feature.
>>> This change fixes that oversight.
>>>
>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>> primary template (that's also missing it).  In addition, it adds
>>> a new class called auto_vec_ncopy that disables copying and
>>> assignment as you prefer.  It also disables copying for
>>> the auto_string_vec class.
>>>
>>> Martin
>>
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-04-27 15:52       ` Martin Sebor
  2021-05-03 21:50         ` [PING][PATCH] " Martin Sebor
@ 2021-05-27 20:53         ` Jason Merrill
  2021-06-01 19:56           ` Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-05-27 20:53 UTC (permalink / raw)
  To: Martin Sebor, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> On 4/27/21 8:04 AM, Richard Biener wrote:
>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>
>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>
>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>> the class manages its own memory but doesn't define (or delete)
>>>>> either special function.  Since I first ran into the problem,
>>>>> auto_vec has grown a move ctor and move assignment from
>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>> assignment operator.
>>>>>
>>>>> The attached patch adds the two special functions to auto_vec along
>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>> that expect copyable and assignable element types and passes bootstrap
>>>>> and regression testing on x86_64-linux.
>>>>
>>>> The question is whether we want such uses to appear since those
>>>> can be quite inefficient?  Thus the option is to delete those 
>>>> operators?
>>>
>>> I would strongly prefer the generic vector class to have the properties
>>> expected of any other generic container: copyable and assignable.  If
>>> we also want another vector type with this restriction I suggest to add
>>> another "noncopyable" type and make that property explicit in its name.
>>> I can submit one in a followup patch if you think we need one.
>>
>> I'm not sure (and not strictly against the copy and assign).  Looking 
>> around
>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>> might be surprising (I added the move capability to match how vec<>
>> is used - as "reference" to a vector)
> 
> The vec base classes are special: they have no ctors at all (because
> of their use in unions).  That's something we might have to live with
> but it's not a model to follow in ordinary containers.

I don't think we have to live with it anymore, now that we're writing C++11.

> The auto_vec class was introduced to fill the need for a conventional
> sequence container with a ctor and dtor.  The missing copy ctor and
> assignment operators were an oversight, not a deliberate feature.
> This change fixes that oversight.
> 
> The revised patch also adds a copy ctor/assignment to the auto_vec
> primary template (that's also missing it).  In addition, it adds
> a new class called auto_vec_ncopy that disables copying and
> assignment as you prefer.

Hmm, adding another class doesn't really help with the confusion richi 
mentions.  And many uses of auto_vec will pass them as vec, which will 
still do a shallow copy.  I think it's probably better to disable the 
copy special members for auto_vec until we fix vec<>.

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-05-27 20:53         ` [PATCH] " Jason Merrill
@ 2021-06-01 19:56           ` Martin Sebor
  2021-06-01 21:38             ` Jason Merrill
  2021-06-02  6:55             ` Richard Biener
  0 siblings, 2 replies; 59+ messages in thread
From: Martin Sebor @ 2021-06-01 19:56 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

On 5/27/21 2:53 PM, Jason Merrill wrote:
> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>
>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>> either special function.  Since I first ran into the problem,
>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>> assignment operator.
>>>>>>
>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>>> that expect copyable and assignable element types and passes 
>>>>>> bootstrap
>>>>>> and regression testing on x86_64-linux.
>>>>>
>>>>> The question is whether we want such uses to appear since those
>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>> operators?
>>>>
>>>> I would strongly prefer the generic vector class to have the properties
>>>> expected of any other generic container: copyable and assignable.  If
>>>> we also want another vector type with this restriction I suggest to add
>>>> another "noncopyable" type and make that property explicit in its name.
>>>> I can submit one in a followup patch if you think we need one.
>>>
>>> I'm not sure (and not strictly against the copy and assign).  Looking 
>>> around
>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>> might be surprising (I added the move capability to match how vec<>
>>> is used - as "reference" to a vector)
>>
>> The vec base classes are special: they have no ctors at all (because
>> of their use in unions).  That's something we might have to live with
>> but it's not a model to follow in ordinary containers.
> 
> I don't think we have to live with it anymore, now that we're writing 
> C++11.
> 
>> The auto_vec class was introduced to fill the need for a conventional
>> sequence container with a ctor and dtor.  The missing copy ctor and
>> assignment operators were an oversight, not a deliberate feature.
>> This change fixes that oversight.
>>
>> The revised patch also adds a copy ctor/assignment to the auto_vec
>> primary template (that's also missing it).  In addition, it adds
>> a new class called auto_vec_ncopy that disables copying and
>> assignment as you prefer.
> 
> Hmm, adding another class doesn't really help with the confusion richi 
> mentions.  And many uses of auto_vec will pass them as vec, which will 
> still do a shallow copy.  I think it's probably better to disable the 
> copy special members for auto_vec until we fix vec<>.

There are at least a couple of problems that get in the way of fixing
all of vec to act like a well-behaved C++ container:

1) The embedded vec has a trailing "flexible" array member with its
instances having different size.  They're initialized by memset and
copied by memcpy.  The class can't have copy ctors or assignments
but it should disable/delete them instead.

2) The heap-based vec is used throughout GCC with the assumption of
shallow copy semantics (not just as function arguments but also as
members of other such POD classes).  This can be changed by providing
copy and move ctors and assignment operators for it, and also for
some of the classes in which it's a member and that are used with
the same assumption.

3) The heap-based vec::block_remove() assumes its elements are PODs.
That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
and tree-vect-patterns.c).

I took a stab at both and while (1) is easy, (2) is shaping up to
be a big and tricky project.  Tricky because it involves using
std::move in places where what's moved is subsequently still used.
I can keep plugging away at it but it won't change the fact that
the embedded and heap-based vecs have different requirements.

It doesn't seem to me that having a safely copyable auto_vec needs
to be put on hold until the rats nest above is untangled.  It won't
make anything worse than it is.  (I have a project that depends on
a sane auto_vec working).

A couple of alternatives to solving this are to use std::vector or
write an equivalent vector class just for GCC.

Martin

> 
> Jason
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-01 19:56           ` Martin Sebor
@ 2021-06-01 21:38             ` Jason Merrill
  2021-06-25 20:51               ` Martin Sebor
  2021-06-02  6:55             ` Richard Biener
  1 sibling, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-06-01 21:38 UTC (permalink / raw)
  To: Martin Sebor, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

On 6/1/21 3:56 PM, Martin Sebor wrote:
> On 5/27/21 2:53 PM, Jason Merrill wrote:
>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>
>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>
>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>> assignment operator.
>>>>>>>
>>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>>> with a few simple tests.  It makes auto_vec safe to use in 
>>>>>>> containers
>>>>>>> that expect copyable and assignable element types and passes 
>>>>>>> bootstrap
>>>>>>> and regression testing on x86_64-linux.
>>>>>>
>>>>>> The question is whether we want such uses to appear since those
>>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>>> operators?
>>>>>
>>>>> I would strongly prefer the generic vector class to have the 
>>>>> properties
>>>>> expected of any other generic container: copyable and assignable.  If
>>>>> we also want another vector type with this restriction I suggest to 
>>>>> add
>>>>> another "noncopyable" type and make that property explicit in its 
>>>>> name.
>>>>> I can submit one in a followup patch if you think we need one.
>>>>
>>>> I'm not sure (and not strictly against the copy and assign).  
>>>> Looking around
>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>> might be surprising (I added the move capability to match how vec<>
>>>> is used - as "reference" to a vector)
>>>
>>> The vec base classes are special: they have no ctors at all (because
>>> of their use in unions).  That's something we might have to live with
>>> but it's not a model to follow in ordinary containers.
>>
>> I don't think we have to live with it anymore, now that we're writing 
>> C++11.
>>
>>> The auto_vec class was introduced to fill the need for a conventional
>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>> assignment operators were an oversight, not a deliberate feature.
>>> This change fixes that oversight.
>>>
>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>> primary template (that's also missing it).  In addition, it adds
>>> a new class called auto_vec_ncopy that disables copying and
>>> assignment as you prefer.
>>
>> Hmm, adding another class doesn't really help with the confusion richi 
>> mentions.  And many uses of auto_vec will pass them as vec, which will 
>> still do a shallow copy.  I think it's probably better to disable the 
>> copy special members for auto_vec until we fix vec<>.
> 
> There are at least a couple of problems that get in the way of fixing
> all of vec to act like a well-behaved C++ container:
> 
> 1) The embedded vec has a trailing "flexible" array member with its
> instances having different size.  They're initialized by memset and
> copied by memcpy.  The class can't have copy ctors or assignments
> but it should disable/delete them instead.
> 
> 2) The heap-based vec is used throughout GCC with the assumption of
> shallow copy semantics (not just as function arguments but also as
> members of other such POD classes).  This can be changed by providing
> copy and move ctors and assignment operators for it, and also for
> some of the classes in which it's a member and that are used with
> the same assumption.
> 
> 3) The heap-based vec::block_remove() assumes its elements are PODs.
> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> and tree-vect-patterns.c).
> 
> I took a stab at both and while (1) is easy, (2) is shaping up to
> be a big and tricky project.  Tricky because it involves using
> std::move in places where what's moved is subsequently still used.
> I can keep plugging away at it but it won't change the fact that
> the embedded and heap-based vecs have different requirements.
> 
> It doesn't seem to me that having a safely copyable auto_vec needs
> to be put on hold until the rats nest above is untangled.  It won't
> make anything worse than it is.  (I have a project that depends on
> a sane auto_vec working).
> 
> A couple of alternatives to solving this are to use std::vector or
> write an equivalent vector class just for GCC.

It occurs to me that another way to work around the issue of passing an 
auto_vec by value as a vec, and thus doing a shallow copy, would be to 
add a vec ctor taking an auto_vec, and delete that.  This would mean if 
you want to pass an auto_vec to a vec interface, it needs to be by 
reference.  We might as well do the same for operator=, though that 
isn't as important.

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-01 19:56           ` Martin Sebor
  2021-06-01 21:38             ` Jason Merrill
@ 2021-06-02  6:55             ` Richard Biener
  2021-06-02 16:04               ` Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-06-02  6:55 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 5/27/21 2:53 PM, Jason Merrill wrote:
> > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> >>>>
> >>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>
> >>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
> >>>>>> the class manages its own memory but doesn't define (or delete)
> >>>>>> either special function.  Since I first ran into the problem,
> >>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>> assignment operator.
> >>>>>>
> >>>>>> The attached patch adds the two special functions to auto_vec along
> >>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
> >>>>>> that expect copyable and assignable element types and passes
> >>>>>> bootstrap
> >>>>>> and regression testing on x86_64-linux.
> >>>>>
> >>>>> The question is whether we want such uses to appear since those
> >>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>> operators?
> >>>>
> >>>> I would strongly prefer the generic vector class to have the properties
> >>>> expected of any other generic container: copyable and assignable.  If
> >>>> we also want another vector type with this restriction I suggest to add
> >>>> another "noncopyable" type and make that property explicit in its name.
> >>>> I can submit one in a followup patch if you think we need one.
> >>>
> >>> I'm not sure (and not strictly against the copy and assign).  Looking
> >>> around
> >>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
> >>> might be surprising (I added the move capability to match how vec<>
> >>> is used - as "reference" to a vector)
> >>
> >> The vec base classes are special: they have no ctors at all (because
> >> of their use in unions).  That's something we might have to live with
> >> but it's not a model to follow in ordinary containers.
> >
> > I don't think we have to live with it anymore, now that we're writing
> > C++11.
> >
> >> The auto_vec class was introduced to fill the need for a conventional
> >> sequence container with a ctor and dtor.  The missing copy ctor and
> >> assignment operators were an oversight, not a deliberate feature.
> >> This change fixes that oversight.
> >>
> >> The revised patch also adds a copy ctor/assignment to the auto_vec
> >> primary template (that's also missing it).  In addition, it adds
> >> a new class called auto_vec_ncopy that disables copying and
> >> assignment as you prefer.
> >
> > Hmm, adding another class doesn't really help with the confusion richi
> > mentions.  And many uses of auto_vec will pass them as vec, which will
> > still do a shallow copy.  I think it's probably better to disable the
> > copy special members for auto_vec until we fix vec<>.
>
> There are at least a couple of problems that get in the way of fixing
> all of vec to act like a well-behaved C++ container:
>
> 1) The embedded vec has a trailing "flexible" array member with its
> instances having different size.  They're initialized by memset and
> copied by memcpy.  The class can't have copy ctors or assignments
> but it should disable/delete them instead.
>
> 2) The heap-based vec is used throughout GCC with the assumption of
> shallow copy semantics (not just as function arguments but also as
> members of other such POD classes).  This can be changed by providing
> copy and move ctors and assignment operators for it, and also for
> some of the classes in which it's a member and that are used with
> the same assumption.
>
> 3) The heap-based vec::block_remove() assumes its elements are PODs.
> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> and tree-vect-patterns.c).
>
> I took a stab at both and while (1) is easy, (2) is shaping up to
> be a big and tricky project.  Tricky because it involves using
> std::move in places where what's moved is subsequently still used.
> I can keep plugging away at it but it won't change the fact that
> the embedded and heap-based vecs have different requirements.

So you figured that neither vec<> nor auto_vec<> are a container like
std::vector.

I'm not sure it makes sense to try to make it so since obviously vec<>
was designed to match the actual needs of GCC.  auto_vec<> was added
to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
to provide initial stack storage.

> It doesn't seem to me that having a safely copyable auto_vec needs
> to be put on hold until the rats nest above is untangled.  It won't
> make anything worse than it is.  (I have a project that depends on
> a sane auto_vec working).

So how does your usage look like?  I can't really figure who'd need
deep copying of a container - note there's vec<>::copy at your
discretion.

> A couple of alternatives to solving this are to use std::vector or
> write an equivalent vector class just for GCC.

As said, can you show the usage that's impossible to do with
the current vec<>/auto_vec<>?

Richard.


> Martin
>
> >
> > Jason
> >
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-02  6:55             ` Richard Biener
@ 2021-06-02 16:04               ` Martin Sebor
  2021-06-03  8:29                 ` Trevor Saunders
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-06-02 16:04 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On 6/2/21 12:55 AM, Richard Biener wrote:
> On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>
>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>
>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>> assignment operator.
>>>>>>>>
>>>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>> bootstrap
>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>
>>>>>>> The question is whether we want such uses to appear since those
>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>> operators?
>>>>>>
>>>>>> I would strongly prefer the generic vector class to have the properties
>>>>>> expected of any other generic container: copyable and assignable.  If
>>>>>> we also want another vector type with this restriction I suggest to add
>>>>>> another "noncopyable" type and make that property explicit in its name.
>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>
>>>>> I'm not sure (and not strictly against the copy and assign).  Looking
>>>>> around
>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>> might be surprising (I added the move capability to match how vec<>
>>>>> is used - as "reference" to a vector)
>>>>
>>>> The vec base classes are special: they have no ctors at all (because
>>>> of their use in unions).  That's something we might have to live with
>>>> but it's not a model to follow in ordinary containers.
>>>
>>> I don't think we have to live with it anymore, now that we're writing
>>> C++11.
>>>
>>>> The auto_vec class was introduced to fill the need for a conventional
>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>> assignment operators were an oversight, not a deliberate feature.
>>>> This change fixes that oversight.
>>>>
>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>> primary template (that's also missing it).  In addition, it adds
>>>> a new class called auto_vec_ncopy that disables copying and
>>>> assignment as you prefer.
>>>
>>> Hmm, adding another class doesn't really help with the confusion richi
>>> mentions.  And many uses of auto_vec will pass them as vec, which will
>>> still do a shallow copy.  I think it's probably better to disable the
>>> copy special members for auto_vec until we fix vec<>.
>>
>> There are at least a couple of problems that get in the way of fixing
>> all of vec to act like a well-behaved C++ container:
>>
>> 1) The embedded vec has a trailing "flexible" array member with its
>> instances having different size.  They're initialized by memset and
>> copied by memcpy.  The class can't have copy ctors or assignments
>> but it should disable/delete them instead.
>>
>> 2) The heap-based vec is used throughout GCC with the assumption of
>> shallow copy semantics (not just as function arguments but also as
>> members of other such POD classes).  This can be changed by providing
>> copy and move ctors and assignment operators for it, and also for
>> some of the classes in which it's a member and that are used with
>> the same assumption.
>>
>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>> and tree-vect-patterns.c).
>>
>> I took a stab at both and while (1) is easy, (2) is shaping up to
>> be a big and tricky project.  Tricky because it involves using
>> std::move in places where what's moved is subsequently still used.
>> I can keep plugging away at it but it won't change the fact that
>> the embedded and heap-based vecs have different requirements.
> 
> So you figured that neither vec<> nor auto_vec<> are a container like
> std::vector.

That's obvious from glancing at their definitions.  I didn't go
through the exercise to figure that out.

> 
> I'm not sure it makes sense to try to make it so since obviously vec<>
> was designed to match the actual needs of GCC.  auto_vec<> was added
> to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> to provide initial stack storage.

The goal was to see if the two vec instances could be made safer
to use but taking advantage of C++ 11 features.  As I mentioned
recently, creating a copy of a vec and modifying it changes it as
well as the original (e.g., by changing a vec argument passed to
it by value a function changes the actual argument in the caller).
That's surprising to most C++ programmers.

My conclusion from the exercise is that although some of the problems
with vec can, and IMO should, be solved, making the heap-based one
a well-behaved C++ 11 container will take considerable effort and
is impossible for the embedded vec.

> 
>> It doesn't seem to me that having a safely copyable auto_vec needs
>> to be put on hold until the rats nest above is untangled.  It won't
>> make anything worse than it is.  (I have a project that depends on
>> a sane auto_vec working).
> 
> So how does your usage look like?  I can't really figure who'd need
> deep copying of a container - note there's vec<>::copy at your
> discretion.
> 
>> A couple of alternatives to solving this are to use std::vector or
>> write an equivalent vector class just for GCC.
> 
> As said, can you show the usage that's impossible to do with
> the current vec<>/auto_vec<>?

The test case in PR 90904 shows a trivial example.  More generally,
using an auto_vec that depends on it being assignable (e.g., storing
an auto_vec in another container like hash_map or auto_vec itself)
is impossible.  Using a plain vec requires manual memory management
and so is error-prone.

But more important, as a C++ code base, GCC should follow the best
practices for the language.  Among the essential ones are using RAII
to manage resources and the Rule of Three (or Five in C++ 11): a class
that defines a dtor should also define a copy ctor and copy assignment
(and move ctor and move assignment in C++).

Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-02 16:04               ` Martin Sebor
@ 2021-06-03  8:29                 ` Trevor Saunders
  2021-06-07  8:51                   ` Richard Biener
  2021-06-07 22:17                   ` Martin Sebor
  0 siblings, 2 replies; 59+ messages in thread
From: Trevor Saunders @ 2021-06-03  8:29 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Richard Biener, Jonathan Wakely, gcc-patches

On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> On 6/2/21 12:55 AM, Richard Biener wrote:
> > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > 
> > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > 
> > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > 
> > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > assignment operator.
> > > > > > > > > 
> > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > bootstrap
> > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > 
> > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > operators?
> > > > > > > 
> > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > 
> > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > around
> > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > is used - as "reference" to a vector)
> > > > > 
> > > > > The vec base classes are special: they have no ctors at all (because
> > > > > of their use in unions).  That's something we might have to live with
> > > > > but it's not a model to follow in ordinary containers.
> > > > 
> > > > I don't think we have to live with it anymore, now that we're writing
> > > > C++11.
> > > > 
> > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > This change fixes that oversight.

I've been away a while, but trying to get back into this, sorry.  It was
definitely an oversight to leave these undefined for the compiler to
provide a default definition of, but I agree with Richi, the better
thing to have done, or do now would be to mark them as deleted and make
auto_vec move only (with copy() for when you really need a deep copy.
> > > > > 
> > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > primary template (that's also missing it).  In addition, it adds
> > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > assignment as you prefer.
> > > > 
> > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > still do a shallow copy.  I think it's probably better to disable the
> > > > copy special members for auto_vec until we fix vec<>.
> > > 
> > > There are at least a couple of problems that get in the way of fixing
> > > all of vec to act like a well-behaved C++ container:
> > > 
> > > 1) The embedded vec has a trailing "flexible" array member with its
> > > instances having different size.  They're initialized by memset and
> > > copied by memcpy.  The class can't have copy ctors or assignments
> > > but it should disable/delete them instead.
> > > 
> > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > shallow copy semantics (not just as function arguments but also as
> > > members of other such POD classes).  This can be changed by providing
> > > copy and move ctors and assignment operators for it, and also for
> > > some of the classes in which it's a member and that are used with
> > > the same assumption.
> > > 
> > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > and tree-vect-patterns.c).
> > > 
> > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > be a big and tricky project.  Tricky because it involves using
> > > std::move in places where what's moved is subsequently still used.
> > > I can keep plugging away at it but it won't change the fact that
> > > the embedded and heap-based vecs have different requirements.
> > 
> > So you figured that neither vec<> nor auto_vec<> are a container like
> > std::vector.
> 
> That's obvious from glancing at their definitions.  I didn't go
> through the exercise to figure that out.
> 
> > 
> > I'm not sure it makes sense to try to make it so since obviously vec<>
> > was designed to match the actual needs of GCC.  auto_vec<> was added
> > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > to provide initial stack storage.
> 
> The goal was to see if the two vec instances could be made safer
> to use but taking advantage of C++ 11 features.  As I mentioned
> recently, creating a copy of a vec and modifying it changes it as
> well as the original (e.g., by changing a vec argument passed to
> it by value a function changes the actual argument in the caller).
> That's surprising to most C++ programmers.

It can probably be improved now with c++11, but while very unfortunate
There is hard requirements on how vec works from existing code using it.

> My conclusion from the exercise is that although some of the problems
> with vec can, and IMO should, be solved, making the heap-based one
> a well-behaved C++ 11 container will take considerable effort and
> is impossible for the embedded vec.

Yes, fortunately things using embedded vec do not at all expect a c++
container, and so don't really mismatch it.  You probably should not be
creating them yourself unless you are creating a new object with an
embedded vector, and you probably don't want to do that.

> > 
> > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > to be put on hold until the rats nest above is untangled.  It won't
> > > make anything worse than it is.  (I have a project that depends on
> > > a sane auto_vec working).
> > 
> > So how does your usage look like?  I can't really figure who'd need
> > deep copying of a container - note there's vec<>::copy at your
> > discretion.
> > 
> > > A couple of alternatives to solving this are to use std::vector or
> > > write an equivalent vector class just for GCC.

imho one of the significant advantages to having our own datastructures
rather than using the standard library is the ability to have a
different API that is less constrained by history, and can make better
choices than standard containers like deleting operators that would
otherwise require deep coppies.  Though certainly they don't always live
up to that like the oversight here of not defining the copy / assignment
operators at all.  Perhaps there's an argument to be made for the
standard containers doing deep coppies that it makes the language easier
to use, but its not all that much easier than .copy(), if that's your
priority c++ probably isn't the right tool for the job, and I doubt it
makes sense for gcc in particular.

> > As said, can you show the usage that's impossible to do with
> > the current vec<>/auto_vec<>?
> 
> The test case in PR 90904 shows a trivial example.  More generally,
> using an auto_vec that depends on it being assignable (e.g., storing
> an auto_vec in another container like hash_map or auto_vec itself)
> is impossible.  Using a plain vec requires manual memory management
> and so is error-prone.

Certainly deleting the copy constructor and assignment operator means
that you can't use them,  but can you show real code where it is a
significant imposition to have to call .copy() rather than using them?
Certainly its a little longer, but deep copies are a bit of a
performance footgun, especially when you have vectors linear in the size
of the function all over, and your goal is to be no worse than
O(N log(N)), meaning you can copy the vector at most log(N) times at
worst.

I would think storing move only objects in auto_vec and hash_* should
work, and if it doesn't should be fixable without introducing overly
easy ways to make deep coppies.

> But more important, as a C++ code base, GCC should follow the best
> practices for the language.  Among the essential ones are using RAII
> to manage resources and the Rule of Three (or Five in C++ 11): a class
> that defines a dtor should also define a copy ctor and copy assignment
> (and move ctor and move assignment in C++).

When discussing the rule of 3/5 at least
https://en.cppreference.com/w/cpp/language/rule_of_three considers
deleting the member to be a form of definition, see the part about non
copiable members and deleting both copy constructor and assignment, in
this case to make the class move only.  Strictly speaking, I suppose its
true that an array of 10k items is copiable, but its also very likely
something to be avoided if at all possible, and doesn't need to be made
easy.

Trev

> 
> Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-03  8:29                 ` Trevor Saunders
@ 2021-06-07  8:51                   ` Richard Biener
  2021-06-07 10:33                     ` Trevor Saunders
  2021-06-07 20:34                     ` Martin Sebor
  2021-06-07 22:17                   ` Martin Sebor
  1 sibling, 2 replies; 59+ messages in thread
From: Richard Biener @ 2021-06-07  8:51 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Martin Sebor, Jonathan Wakely, gcc-patches

On Thu, Jun 3, 2021 at 10:29 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> > On 6/2/21 12:55 AM, Richard Biener wrote:
> > > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > >
> > > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > >
> > > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > >
> > > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > > assignment operator.
> > > > > > > > > >
> > > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > > bootstrap
> > > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > >
> > > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > > operators?
> > > > > > > >
> > > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > >
> > > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > > around
> > > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > > is used - as "reference" to a vector)
> > > > > >
> > > > > > The vec base classes are special: they have no ctors at all (because
> > > > > > of their use in unions).  That's something we might have to live with
> > > > > > but it's not a model to follow in ordinary containers.
> > > > >
> > > > > I don't think we have to live with it anymore, now that we're writing
> > > > > C++11.
> > > > >
> > > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > > This change fixes that oversight.
>
> I've been away a while, but trying to get back into this, sorry.  It was
> definitely an oversight to leave these undefined for the compiler to
> provide a default definition of, but I agree with Richi, the better
> thing to have done, or do now would be to mark them as deleted and make
> auto_vec move only (with copy() for when you really need a deep copy.
> > > > > >
> > > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > > primary template (that's also missing it).  In addition, it adds
> > > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > > assignment as you prefer.
> > > > >
> > > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > > still do a shallow copy.  I think it's probably better to disable the
> > > > > copy special members for auto_vec until we fix vec<>.
> > > >
> > > > There are at least a couple of problems that get in the way of fixing
> > > > all of vec to act like a well-behaved C++ container:
> > > >
> > > > 1) The embedded vec has a trailing "flexible" array member with its
> > > > instances having different size.  They're initialized by memset and
> > > > copied by memcpy.  The class can't have copy ctors or assignments
> > > > but it should disable/delete them instead.
> > > >
> > > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > > shallow copy semantics (not just as function arguments but also as
> > > > members of other such POD classes).  This can be changed by providing
> > > > copy and move ctors and assignment operators for it, and also for
> > > > some of the classes in which it's a member and that are used with
> > > > the same assumption.
> > > >
> > > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > > and tree-vect-patterns.c).
> > > >
> > > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > > be a big and tricky project.  Tricky because it involves using
> > > > std::move in places where what's moved is subsequently still used.
> > > > I can keep plugging away at it but it won't change the fact that
> > > > the embedded and heap-based vecs have different requirements.
> > >
> > > So you figured that neither vec<> nor auto_vec<> are a container like
> > > std::vector.
> >
> > That's obvious from glancing at their definitions.  I didn't go
> > through the exercise to figure that out.
> >
> > >
> > > I'm not sure it makes sense to try to make it so since obviously vec<>
> > > was designed to match the actual needs of GCC.  auto_vec<> was added
> > > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > > to provide initial stack storage.
> >
> > The goal was to see if the two vec instances could be made safer
> > to use but taking advantage of C++ 11 features.  As I mentioned
> > recently, creating a copy of a vec and modifying it changes it as
> > well as the original (e.g., by changing a vec argument passed to
> > it by value a function changes the actual argument in the caller).
> > That's surprising to most C++ programmers.
>
> It can probably be improved now with c++11, but while very unfortunate
> There is hard requirements on how vec works from existing code using it.
>
> > My conclusion from the exercise is that although some of the problems
> > with vec can, and IMO should, be solved, making the heap-based one
> > a well-behaved C++ 11 container will take considerable effort and
> > is impossible for the embedded vec.
>
> Yes, fortunately things using embedded vec do not at all expect a c++
> container, and so don't really mismatch it.  You probably should not be
> creating them yourself unless you are creating a new object with an
> embedded vector, and you probably don't want to do that.
>
> > >
> > > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > > to be put on hold until the rats nest above is untangled.  It won't
> > > > make anything worse than it is.  (I have a project that depends on
> > > > a sane auto_vec working).
> > >
> > > So how does your usage look like?  I can't really figure who'd need
> > > deep copying of a container - note there's vec<>::copy at your
> > > discretion.
> > >
> > > > A couple of alternatives to solving this are to use std::vector or
> > > > write an equivalent vector class just for GCC.
>
> imho one of the significant advantages to having our own datastructures
> rather than using the standard library is the ability to have a
> different API that is less constrained by history, and can make better
> choices than standard containers like deleting operators that would
> otherwise require deep coppies.  Though certainly they don't always live
> up to that like the oversight here of not defining the copy / assignment
> operators at all.  Perhaps there's an argument to be made for the
> standard containers doing deep coppies that it makes the language easier
> to use, but its not all that much easier than .copy(), if that's your
> priority c++ probably isn't the right tool for the job, and I doubt it
> makes sense for gcc in particular.
>
> > > As said, can you show the usage that's impossible to do with
> > > the current vec<>/auto_vec<>?
> >
> > The test case in PR 90904 shows a trivial example.  More generally,
> > using an auto_vec that depends on it being assignable (e.g., storing
> > an auto_vec in another container like hash_map or auto_vec itself)
> > is impossible.  Using a plain vec requires manual memory management
> > and so is error-prone.

Btw, I remember once trying to make hash_map<int, auto_vec<int, 1> >
work which pre-dated C++11 allowance (but I found a much nicer,
albeit non-"C++" solution using obstacks and linked lists .. heh).  That
might work nowadays if we fix hash_map re-allocation to use
std::move and add move CTORs to the auto_vec<int, N> template
(I refrained from that when I added them to the , 0 specialization
since even moving would mean moving quite some storage).

> Certainly deleting the copy constructor and assignment operator means
> that you can't use them,  but can you show real code where it is a
> significant imposition to have to call .copy() rather than using them?
> Certainly its a little longer, but deep copies are a bit of a
> performance footgun, especially when you have vectors linear in the size
> of the function all over, and your goal is to be no worse than
> O(N log(N)), meaning you can copy the vector at most log(N) times at
> worst.
>
> I would think storing move only objects in auto_vec and hash_* should
> work, and if it doesn't should be fixable without introducing overly
> easy ways to make deep coppies.
>
> > But more important, as a C++ code base, GCC should follow the best
> > practices for the language.  Among the essential ones are using RAII
> > to manage resources and the Rule of Three (or Five in C++ 11): a class
> > that defines a dtor should also define a copy ctor and copy assignment
> > (and move ctor and move assignment in C++).
>
> When discussing the rule of 3/5 at least
> https://en.cppreference.com/w/cpp/language/rule_of_three considers
> deleting the member to be a form of definition, see the part about non
> copiable members and deleting both copy constructor and assignment, in
> this case to make the class move only.  Strictly speaking, I suppose its
> true that an array of 10k items is copiable, but its also very likely
> something to be avoided if at all possible, and doesn't need to be made
> easy.
>
> Trev
>
> >
> > Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-07  8:51                   ` Richard Biener
@ 2021-06-07 10:33                     ` Trevor Saunders
  2021-06-07 13:33                       ` Richard Biener
  2021-06-07 20:34                     ` Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Trevor Saunders @ 2021-06-07 10:33 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jonathan Wakely, gcc-patches

On Mon, Jun 07, 2021 at 10:51:18AM +0200, Richard Biener via Gcc-patches wrote:
> On Thu, Jun 3, 2021 at 10:29 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> >
> > On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> > > On 6/2/21 12:55 AM, Richard Biener wrote:
> > > > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > >
> > > > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > > >
> > > > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > > >
> > > > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > > > assignment operator.
> > > > > > > > > > >
> > > > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > > > bootstrap
> > > > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > > >
> > > > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > > > operators?
> > > > > > > > >
> > > > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > > >
> > > > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > > > around
> > > > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > > > is used - as "reference" to a vector)
> > > > > > >
> > > > > > > The vec base classes are special: they have no ctors at all (because
> > > > > > > of their use in unions).  That's something we might have to live with
> > > > > > > but it's not a model to follow in ordinary containers.
> > > > > >
> > > > > > I don't think we have to live with it anymore, now that we're writing
> > > > > > C++11.
> > > > > >
> > > > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > > > This change fixes that oversight.
> >
> > I've been away a while, but trying to get back into this, sorry.  It was
> > definitely an oversight to leave these undefined for the compiler to
> > provide a default definition of, but I agree with Richi, the better
> > thing to have done, or do now would be to mark them as deleted and make
> > auto_vec move only (with copy() for when you really need a deep copy.
> > > > > > >
> > > > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > > > primary template (that's also missing it).  In addition, it adds
> > > > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > > > assignment as you prefer.
> > > > > >
> > > > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > > > still do a shallow copy.  I think it's probably better to disable the
> > > > > > copy special members for auto_vec until we fix vec<>.
> > > > >
> > > > > There are at least a couple of problems that get in the way of fixing
> > > > > all of vec to act like a well-behaved C++ container:
> > > > >
> > > > > 1) The embedded vec has a trailing "flexible" array member with its
> > > > > instances having different size.  They're initialized by memset and
> > > > > copied by memcpy.  The class can't have copy ctors or assignments
> > > > > but it should disable/delete them instead.
> > > > >
> > > > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > > > shallow copy semantics (not just as function arguments but also as
> > > > > members of other such POD classes).  This can be changed by providing
> > > > > copy and move ctors and assignment operators for it, and also for
> > > > > some of the classes in which it's a member and that are used with
> > > > > the same assumption.
> > > > >
> > > > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > > > and tree-vect-patterns.c).
> > > > >
> > > > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > > > be a big and tricky project.  Tricky because it involves using
> > > > > std::move in places where what's moved is subsequently still used.
> > > > > I can keep plugging away at it but it won't change the fact that
> > > > > the embedded and heap-based vecs have different requirements.
> > > >
> > > > So you figured that neither vec<> nor auto_vec<> are a container like
> > > > std::vector.
> > >
> > > That's obvious from glancing at their definitions.  I didn't go
> > > through the exercise to figure that out.
> > >
> > > >
> > > > I'm not sure it makes sense to try to make it so since obviously vec<>
> > > > was designed to match the actual needs of GCC.  auto_vec<> was added
> > > > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > > > to provide initial stack storage.
> > >
> > > The goal was to see if the two vec instances could be made safer
> > > to use but taking advantage of C++ 11 features.  As I mentioned
> > > recently, creating a copy of a vec and modifying it changes it as
> > > well as the original (e.g., by changing a vec argument passed to
> > > it by value a function changes the actual argument in the caller).
> > > That's surprising to most C++ programmers.
> >
> > It can probably be improved now with c++11, but while very unfortunate
> > There is hard requirements on how vec works from existing code using it.
> >
> > > My conclusion from the exercise is that although some of the problems
> > > with vec can, and IMO should, be solved, making the heap-based one
> > > a well-behaved C++ 11 container will take considerable effort and
> > > is impossible for the embedded vec.
> >
> > Yes, fortunately things using embedded vec do not at all expect a c++
> > container, and so don't really mismatch it.  You probably should not be
> > creating them yourself unless you are creating a new object with an
> > embedded vector, and you probably don't want to do that.
> >
> > > >
> > > > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > > > to be put on hold until the rats nest above is untangled.  It won't
> > > > > make anything worse than it is.  (I have a project that depends on
> > > > > a sane auto_vec working).
> > > >
> > > > So how does your usage look like?  I can't really figure who'd need
> > > > deep copying of a container - note there's vec<>::copy at your
> > > > discretion.
> > > >
> > > > > A couple of alternatives to solving this are to use std::vector or
> > > > > write an equivalent vector class just for GCC.
> >
> > imho one of the significant advantages to having our own datastructures
> > rather than using the standard library is the ability to have a
> > different API that is less constrained by history, and can make better
> > choices than standard containers like deleting operators that would
> > otherwise require deep coppies.  Though certainly they don't always live
> > up to that like the oversight here of not defining the copy / assignment
> > operators at all.  Perhaps there's an argument to be made for the
> > standard containers doing deep coppies that it makes the language easier
> > to use, but its not all that much easier than .copy(), if that's your
> > priority c++ probably isn't the right tool for the job, and I doubt it
> > makes sense for gcc in particular.
> >
> > > > As said, can you show the usage that's impossible to do with
> > > > the current vec<>/auto_vec<>?
> > >
> > > The test case in PR 90904 shows a trivial example.  More generally,
> > > using an auto_vec that depends on it being assignable (e.g., storing
> > > an auto_vec in another container like hash_map or auto_vec itself)
> > > is impossible.  Using a plain vec requires manual memory management
> > > and so is error-prone.
> 
> Btw, I remember once trying to make hash_map<int, auto_vec<int, 1> >
> work which pre-dated C++11 allowance (but I found a much nicer,
> albeit non-"C++" solution using obstacks and linked lists .. heh).  That
> might work nowadays if we fix hash_map re-allocation to use
> std::move and add move CTORs to the auto_vec<int, N> template
> (I refrained from that when I added them to the , 0 specialization
> since even moving would mean moving quite some storage).

Yeah, it should be possible (with whatever work it takes to make all the
hash table users compatible with move not memcpy), but it certainly
makes sense for hash_* to move elements around.  For auto_vec<T, N> I'm
kind of on the fence if its a good idea, its sort of a copy not a move,
but I suppose it would move the contents rather than copying them which
might be important if you have auto_vec<vec<treee>, 5> where the inner
vector has a thousand elements.  So I suppose its best to first worry
about move in hash_* and worry about moving auto_vec<T, N> later when
its necessary.

Trev

> 
> > Certainly deleting the copy constructor and assignment operator means
> > that you can't use them,  but can you show real code where it is a
> > significant imposition to have to call .copy() rather than using them?
> > Certainly its a little longer, but deep copies are a bit of a
> > performance footgun, especially when you have vectors linear in the size
> > of the function all over, and your goal is to be no worse than
> > O(N log(N)), meaning you can copy the vector at most log(N) times at
> > worst.
> >
> > I would think storing move only objects in auto_vec and hash_* should
> > work, and if it doesn't should be fixable without introducing overly
> > easy ways to make deep coppies.
> >
> > > But more important, as a C++ code base, GCC should follow the best
> > > practices for the language.  Among the essential ones are using RAII
> > > to manage resources and the Rule of Three (or Five in C++ 11): a class
> > > that defines a dtor should also define a copy ctor and copy assignment
> > > (and move ctor and move assignment in C++).
> >
> > When discussing the rule of 3/5 at least
> > https://en.cppreference.com/w/cpp/language/rule_of_three considers
> > deleting the member to be a form of definition, see the part about non
> > copiable members and deleting both copy constructor and assignment, in
> > this case to make the class move only.  Strictly speaking, I suppose its
> > true that an array of 10k items is copiable, but its also very likely
> > something to be avoided if at all possible, and doesn't need to be made
> > easy.
> >
> > Trev
> >
> > >
> > > Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-07 10:33                     ` Trevor Saunders
@ 2021-06-07 13:33                       ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2021-06-07 13:33 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Jonathan Wakely, gcc-patches

On Mon, Jun 7, 2021 at 12:33 PM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> On Mon, Jun 07, 2021 at 10:51:18AM +0200, Richard Biener via Gcc-patches wrote:
> > On Thu, Jun 3, 2021 at 10:29 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > >
> > > On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> > > > On 6/2/21 12:55 AM, Richard Biener wrote:
> > > > > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > >
> > > > > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > > > >
> > > > > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > > > >
> > > > > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > > > > assignment operator.
> > > > > > > > > > > >
> > > > > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > > > > bootstrap
> > > > > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > > > >
> > > > > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > > > > operators?
> > > > > > > > > >
> > > > > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > > > >
> > > > > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > > > > around
> > > > > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > > > > is used - as "reference" to a vector)
> > > > > > > >
> > > > > > > > The vec base classes are special: they have no ctors at all (because
> > > > > > > > of their use in unions).  That's something we might have to live with
> > > > > > > > but it's not a model to follow in ordinary containers.
> > > > > > >
> > > > > > > I don't think we have to live with it anymore, now that we're writing
> > > > > > > C++11.
> > > > > > >
> > > > > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > > > > This change fixes that oversight.
> > >
> > > I've been away a while, but trying to get back into this, sorry.  It was
> > > definitely an oversight to leave these undefined for the compiler to
> > > provide a default definition of, but I agree with Richi, the better
> > > thing to have done, or do now would be to mark them as deleted and make
> > > auto_vec move only (with copy() for when you really need a deep copy.
> > > > > > > >
> > > > > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > > > > primary template (that's also missing it).  In addition, it adds
> > > > > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > > > > assignment as you prefer.
> > > > > > >
> > > > > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > > > > still do a shallow copy.  I think it's probably better to disable the
> > > > > > > copy special members for auto_vec until we fix vec<>.
> > > > > >
> > > > > > There are at least a couple of problems that get in the way of fixing
> > > > > > all of vec to act like a well-behaved C++ container:
> > > > > >
> > > > > > 1) The embedded vec has a trailing "flexible" array member with its
> > > > > > instances having different size.  They're initialized by memset and
> > > > > > copied by memcpy.  The class can't have copy ctors or assignments
> > > > > > but it should disable/delete them instead.
> > > > > >
> > > > > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > > > > shallow copy semantics (not just as function arguments but also as
> > > > > > members of other such POD classes).  This can be changed by providing
> > > > > > copy and move ctors and assignment operators for it, and also for
> > > > > > some of the classes in which it's a member and that are used with
> > > > > > the same assumption.
> > > > > >
> > > > > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > > > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > > > > and tree-vect-patterns.c).
> > > > > >
> > > > > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > > > > be a big and tricky project.  Tricky because it involves using
> > > > > > std::move in places where what's moved is subsequently still used.
> > > > > > I can keep plugging away at it but it won't change the fact that
> > > > > > the embedded and heap-based vecs have different requirements.
> > > > >
> > > > > So you figured that neither vec<> nor auto_vec<> are a container like
> > > > > std::vector.
> > > >
> > > > That's obvious from glancing at their definitions.  I didn't go
> > > > through the exercise to figure that out.
> > > >
> > > > >
> > > > > I'm not sure it makes sense to try to make it so since obviously vec<>
> > > > > was designed to match the actual needs of GCC.  auto_vec<> was added
> > > > > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > > > > to provide initial stack storage.
> > > >
> > > > The goal was to see if the two vec instances could be made safer
> > > > to use but taking advantage of C++ 11 features.  As I mentioned
> > > > recently, creating a copy of a vec and modifying it changes it as
> > > > well as the original (e.g., by changing a vec argument passed to
> > > > it by value a function changes the actual argument in the caller).
> > > > That's surprising to most C++ programmers.
> > >
> > > It can probably be improved now with c++11, but while very unfortunate
> > > There is hard requirements on how vec works from existing code using it.
> > >
> > > > My conclusion from the exercise is that although some of the problems
> > > > with vec can, and IMO should, be solved, making the heap-based one
> > > > a well-behaved C++ 11 container will take considerable effort and
> > > > is impossible for the embedded vec.
> > >
> > > Yes, fortunately things using embedded vec do not at all expect a c++
> > > container, and so don't really mismatch it.  You probably should not be
> > > creating them yourself unless you are creating a new object with an
> > > embedded vector, and you probably don't want to do that.
> > >
> > > > >
> > > > > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > > > > to be put on hold until the rats nest above is untangled.  It won't
> > > > > > make anything worse than it is.  (I have a project that depends on
> > > > > > a sane auto_vec working).
> > > > >
> > > > > So how does your usage look like?  I can't really figure who'd need
> > > > > deep copying of a container - note there's vec<>::copy at your
> > > > > discretion.
> > > > >
> > > > > > A couple of alternatives to solving this are to use std::vector or
> > > > > > write an equivalent vector class just for GCC.
> > >
> > > imho one of the significant advantages to having our own datastructures
> > > rather than using the standard library is the ability to have a
> > > different API that is less constrained by history, and can make better
> > > choices than standard containers like deleting operators that would
> > > otherwise require deep coppies.  Though certainly they don't always live
> > > up to that like the oversight here of not defining the copy / assignment
> > > operators at all.  Perhaps there's an argument to be made for the
> > > standard containers doing deep coppies that it makes the language easier
> > > to use, but its not all that much easier than .copy(), if that's your
> > > priority c++ probably isn't the right tool for the job, and I doubt it
> > > makes sense for gcc in particular.
> > >
> > > > > As said, can you show the usage that's impossible to do with
> > > > > the current vec<>/auto_vec<>?
> > > >
> > > > The test case in PR 90904 shows a trivial example.  More generally,
> > > > using an auto_vec that depends on it being assignable (e.g., storing
> > > > an auto_vec in another container like hash_map or auto_vec itself)
> > > > is impossible.  Using a plain vec requires manual memory management
> > > > and so is error-prone.
> >
> > Btw, I remember once trying to make hash_map<int, auto_vec<int, 1> >
> > work which pre-dated C++11 allowance (but I found a much nicer,
> > albeit non-"C++" solution using obstacks and linked lists .. heh).  That
> > might work nowadays if we fix hash_map re-allocation to use
> > std::move and add move CTORs to the auto_vec<int, N> template
> > (I refrained from that when I added them to the , 0 specialization
> > since even moving would mean moving quite some storage).
>
> Yeah, it should be possible (with whatever work it takes to make all the
> hash table users compatible with move not memcpy), but it certainly
> makes sense for hash_* to move elements around.  For auto_vec<T, N> I'm
> kind of on the fence if its a good idea, its sort of a copy not a move,
> but I suppose it would move the contents rather than copying them which
> might be important if you have auto_vec<vec<treee>, 5> where the inner
> vector has a thousand elements.  So I suppose its best to first worry
> about move in hash_* and worry about moving auto_vec<T, N> later when
> its necessary.

In my case in 99% of the cases the auto-storage of capacity 1 was enough
but I wanted the nice allocation and bounds-checking of vec<> plus avoid
an indirection as happening with hash_map<int, vec<int> *>.  The tricky
bit that breaks upon re-allocation of the hash-map is the pointer to the
auto-storage which is what the move CTOR would need to fixup.

Richard.

> Trev
>
> >
> > > Certainly deleting the copy constructor and assignment operator means
> > > that you can't use them,  but can you show real code where it is a
> > > significant imposition to have to call .copy() rather than using them?
> > > Certainly its a little longer, but deep copies are a bit of a
> > > performance footgun, especially when you have vectors linear in the size
> > > of the function all over, and your goal is to be no worse than
> > > O(N log(N)), meaning you can copy the vector at most log(N) times at
> > > worst.
> > >
> > > I would think storing move only objects in auto_vec and hash_* should
> > > work, and if it doesn't should be fixable without introducing overly
> > > easy ways to make deep coppies.
> > >
> > > > But more important, as a C++ code base, GCC should follow the best
> > > > practices for the language.  Among the essential ones are using RAII
> > > > to manage resources and the Rule of Three (or Five in C++ 11): a class
> > > > that defines a dtor should also define a copy ctor and copy assignment
> > > > (and move ctor and move assignment in C++).
> > >
> > > When discussing the rule of 3/5 at least
> > > https://en.cppreference.com/w/cpp/language/rule_of_three considers
> > > deleting the member to be a form of definition, see the part about non
> > > copiable members and deleting both copy constructor and assignment, in
> > > this case to make the class move only.  Strictly speaking, I suppose its
> > > true that an array of 10k items is copiable, but its also very likely
> > > something to be avoided if at all possible, and doesn't need to be made
> > > easy.
> > >
> > > Trev
> > >
> > > >
> > > > Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-07  8:51                   ` Richard Biener
  2021-06-07 10:33                     ` Trevor Saunders
@ 2021-06-07 20:34                     ` Martin Sebor
  2021-06-08  3:26                       ` Trevor Saunders
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-06-07 20:34 UTC (permalink / raw)
  To: Richard Biener, Trevor Saunders; +Cc: Jonathan Wakely, gcc-patches

On 6/7/21 2:51 AM, Richard Biener wrote:
> On Thu, Jun 3, 2021 at 10:29 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>>
>> On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
>>> On 6/2/21 12:55 AM, Richard Biener wrote:
>>>> On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>
>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>>>>
>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>
>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>> assignment operator.
>>>>>>>>>>>
>>>>>>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>> bootstrap
>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>
>>>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>> operators?
>>>>>>>>>
>>>>>>>>> I would strongly prefer the generic vector class to have the properties
>>>>>>>>> expected of any other generic container: copyable and assignable.  If
>>>>>>>>> we also want another vector type with this restriction I suggest to add
>>>>>>>>> another "noncopyable" type and make that property explicit in its name.
>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>
>>>>>>>> I'm not sure (and not strictly against the copy and assign).  Looking
>>>>>>>> around
>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>>>>> might be surprising (I added the move capability to match how vec<>
>>>>>>>> is used - as "reference" to a vector)
>>>>>>>
>>>>>>> The vec base classes are special: they have no ctors at all (because
>>>>>>> of their use in unions).  That's something we might have to live with
>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>
>>>>>> I don't think we have to live with it anymore, now that we're writing
>>>>>> C++11.
>>>>>>
>>>>>>> The auto_vec class was introduced to fill the need for a conventional
>>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>>> This change fixes that oversight.
>>
>> I've been away a while, but trying to get back into this, sorry.  It was
>> definitely an oversight to leave these undefined for the compiler to
>> provide a default definition of, but I agree with Richi, the better
>> thing to have done, or do now would be to mark them as deleted and make
>> auto_vec move only (with copy() for when you really need a deep copy.
>>>>>>>
>>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>> assignment as you prefer.
>>>>>>
>>>>>> Hmm, adding another class doesn't really help with the confusion richi
>>>>>> mentions.  And many uses of auto_vec will pass them as vec, which will
>>>>>> still do a shallow copy.  I think it's probably better to disable the
>>>>>> copy special members for auto_vec until we fix vec<>.
>>>>>
>>>>> There are at least a couple of problems that get in the way of fixing
>>>>> all of vec to act like a well-behaved C++ container:
>>>>>
>>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>>> instances having different size.  They're initialized by memset and
>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>> but it should disable/delete them instead.
>>>>>
>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>>> shallow copy semantics (not just as function arguments but also as
>>>>> members of other such POD classes).  This can be changed by providing
>>>>> copy and move ctors and assignment operators for it, and also for
>>>>> some of the classes in which it's a member and that are used with
>>>>> the same assumption.
>>>>>
>>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>> and tree-vect-patterns.c).
>>>>>
>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>> be a big and tricky project.  Tricky because it involves using
>>>>> std::move in places where what's moved is subsequently still used.
>>>>> I can keep plugging away at it but it won't change the fact that
>>>>> the embedded and heap-based vecs have different requirements.
>>>>
>>>> So you figured that neither vec<> nor auto_vec<> are a container like
>>>> std::vector.
>>>
>>> That's obvious from glancing at their definitions.  I didn't go
>>> through the exercise to figure that out.
>>>
>>>>
>>>> I'm not sure it makes sense to try to make it so since obviously vec<>
>>>> was designed to match the actual needs of GCC.  auto_vec<> was added
>>>> to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
>>>> to provide initial stack storage.
>>>
>>> The goal was to see if the two vec instances could be made safer
>>> to use but taking advantage of C++ 11 features.  As I mentioned
>>> recently, creating a copy of a vec and modifying it changes it as
>>> well as the original (e.g., by changing a vec argument passed to
>>> it by value a function changes the actual argument in the caller).
>>> That's surprising to most C++ programmers.
>>
>> It can probably be improved now with c++11, but while very unfortunate
>> There is hard requirements on how vec works from existing code using it.
>>
>>> My conclusion from the exercise is that although some of the problems
>>> with vec can, and IMO should, be solved, making the heap-based one
>>> a well-behaved C++ 11 container will take considerable effort and
>>> is impossible for the embedded vec.
>>
>> Yes, fortunately things using embedded vec do not at all expect a c++
>> container, and so don't really mismatch it.  You probably should not be
>> creating them yourself unless you are creating a new object with an
>> embedded vector, and you probably don't want to do that.
>>
>>>>
>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>>> make anything worse than it is.  (I have a project that depends on
>>>>> a sane auto_vec working).
>>>>
>>>> So how does your usage look like?  I can't really figure who'd need
>>>> deep copying of a container - note there's vec<>::copy at your
>>>> discretion.
>>>>
>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>> write an equivalent vector class just for GCC.
>>
>> imho one of the significant advantages to having our own datastructures
>> rather than using the standard library is the ability to have a
>> different API that is less constrained by history, and can make better
>> choices than standard containers like deleting operators that would
>> otherwise require deep coppies.  Though certainly they don't always live
>> up to that like the oversight here of not defining the copy / assignment
>> operators at all.  Perhaps there's an argument to be made for the
>> standard containers doing deep coppies that it makes the language easier
>> to use, but its not all that much easier than .copy(), if that's your
>> priority c++ probably isn't the right tool for the job, and I doubt it
>> makes sense for gcc in particular.
>>
>>>> As said, can you show the usage that's impossible to do with
>>>> the current vec<>/auto_vec<>?
>>>
>>> The test case in PR 90904 shows a trivial example.  More generally,
>>> using an auto_vec that depends on it being assignable (e.g., storing
>>> an auto_vec in another container like hash_map or auto_vec itself)
>>> is impossible.  Using a plain vec requires manual memory management
>>> and so is error-prone.
> 
> Btw, I remember once trying to make hash_map<int, auto_vec<int, 1> >
> work which pre-dated C++11 allowance (but I found a much nicer,
> albeit non-"C++" solution using obstacks and linked lists .. heh).  That
> might work nowadays if we fix hash_map re-allocation to use
> std::move and add move CTORs to the auto_vec<int, N> template
> (I refrained from that when I added them to the , 0 specialization
> since even moving would mean moving quite some storage).

hash_map relies on its elements being copy-assignable.  To avoid that
it needs to overload its put() member to take an rvalue reference and
forward the argument to the move ctor.  Those would be good changes
to make but they alone wouldn't make using a hash_map easy to use
with a move-only type because the move overload is only viable in
limited contexts.  E.g., it wouldn't make this common use case valid:

   void f (hash_map<int, Moveable> &m, const Moveable &x)
   {
     m.put (1, x);
   }

Sequences like vec (and auto_vec) rely on their elements having a copy
ctor and copy assignment to grow by inserting elements in the middle.
But similar to hash_map, using them also depends on being able to copy
the elements (e.g., call v.push_back(x) in the above).

In general, move semantics are a special case, an optimization, of copy
semantics.  There are use cases for moveable-only types but they're not
the default and they limit the usability of those types.

Martin

> 
>> Certainly deleting the copy constructor and assignment operator means
>> that you can't use them,  but can you show real code where it is a
>> significant imposition to have to call .copy() rather than using them?
>> Certainly its a little longer, but deep copies are a bit of a
>> performance footgun, especially when you have vectors linear in the size
>> of the function all over, and your goal is to be no worse than
>> O(N log(N)), meaning you can copy the vector at most log(N) times at
>> worst.
>>
>> I would think storing move only objects in auto_vec and hash_* should
>> work, and if it doesn't should be fixable without introducing overly
>> easy ways to make deep coppies.
>>
>>> But more important, as a C++ code base, GCC should follow the best
>>> practices for the language.  Among the essential ones are using RAII
>>> to manage resources and the Rule of Three (or Five in C++ 11): a class
>>> that defines a dtor should also define a copy ctor and copy assignment
>>> (and move ctor and move assignment in C++).
>>
>> When discussing the rule of 3/5 at least
>> https://en.cppreference.com/w/cpp/language/rule_of_three considers
>> deleting the member to be a form of definition, see the part about non
>> copiable members and deleting both copy constructor and assignment, in
>> this case to make the class move only.  Strictly speaking, I suppose its
>> true that an array of 10k items is copiable, but its also very likely
>> something to be avoided if at all possible, and doesn't need to be made
>> easy.
>>
>> Trev
>>
>>>
>>> Martin


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-03  8:29                 ` Trevor Saunders
  2021-06-07  8:51                   ` Richard Biener
@ 2021-06-07 22:17                   ` Martin Sebor
  2021-06-08  2:41                     ` Trevor Saunders
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-06-07 22:17 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Richard Biener, Jonathan Wakely, gcc-patches

On 6/3/21 2:29 AM, Trevor Saunders wrote:
> On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
>> On 6/2/21 12:55 AM, Richard Biener wrote:
>>> On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>>>
>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>
>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>> assignment operator.
>>>>>>>>>>
>>>>>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in containers
>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>> bootstrap
>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>
>>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>> operators?
>>>>>>>>
>>>>>>>> I would strongly prefer the generic vector class to have the properties
>>>>>>>> expected of any other generic container: copyable and assignable.  If
>>>>>>>> we also want another vector type with this restriction I suggest to add
>>>>>>>> another "noncopyable" type and make that property explicit in its name.
>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>
>>>>>>> I'm not sure (and not strictly against the copy and assign).  Looking
>>>>>>> around
>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>>>> might be surprising (I added the move capability to match how vec<>
>>>>>>> is used - as "reference" to a vector)
>>>>>>
>>>>>> The vec base classes are special: they have no ctors at all (because
>>>>>> of their use in unions).  That's something we might have to live with
>>>>>> but it's not a model to follow in ordinary containers.
>>>>>
>>>>> I don't think we have to live with it anymore, now that we're writing
>>>>> C++11.
>>>>>
>>>>>> The auto_vec class was introduced to fill the need for a conventional
>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>> This change fixes that oversight.
> 
> I've been away a while, but trying to get back into this, sorry.  It was
> definitely an oversight to leave these undefined for the compiler to
> provide a default definition of, but I agree with Richi, the better
> thing to have done, or do now would be to mark them as deleted and make
> auto_vec move only (with copy() for when you really need a deep copy.
>>>>>>
>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>> assignment as you prefer.
>>>>>
>>>>> Hmm, adding another class doesn't really help with the confusion richi
>>>>> mentions.  And many uses of auto_vec will pass them as vec, which will
>>>>> still do a shallow copy.  I think it's probably better to disable the
>>>>> copy special members for auto_vec until we fix vec<>.
>>>>
>>>> There are at least a couple of problems that get in the way of fixing
>>>> all of vec to act like a well-behaved C++ container:
>>>>
>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>> instances having different size.  They're initialized by memset and
>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>> but it should disable/delete them instead.
>>>>
>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>> shallow copy semantics (not just as function arguments but also as
>>>> members of other such POD classes).  This can be changed by providing
>>>> copy and move ctors and assignment operators for it, and also for
>>>> some of the classes in which it's a member and that are used with
>>>> the same assumption.
>>>>
>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>> and tree-vect-patterns.c).
>>>>
>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>> be a big and tricky project.  Tricky because it involves using
>>>> std::move in places where what's moved is subsequently still used.
>>>> I can keep plugging away at it but it won't change the fact that
>>>> the embedded and heap-based vecs have different requirements.
>>>
>>> So you figured that neither vec<> nor auto_vec<> are a container like
>>> std::vector.
>>
>> That's obvious from glancing at their definitions.  I didn't go
>> through the exercise to figure that out.
>>
>>>
>>> I'm not sure it makes sense to try to make it so since obviously vec<>
>>> was designed to match the actual needs of GCC.  auto_vec<> was added
>>> to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
>>> to provide initial stack storage.
>>
>> The goal was to see if the two vec instances could be made safer
>> to use but taking advantage of C++ 11 features.  As I mentioned
>> recently, creating a copy of a vec and modifying it changes it as
>> well as the original (e.g., by changing a vec argument passed to
>> it by value a function changes the actual argument in the caller).
>> That's surprising to most C++ programmers.
> 
> It can probably be improved now with c++11, but while very unfortunate
> There is hard requirements on how vec works from existing code using it.
> 
>> My conclusion from the exercise is that although some of the problems
>> with vec can, and IMO should, be solved, making the heap-based one
>> a well-behaved C++ 11 container will take considerable effort and
>> is impossible for the embedded vec.
> 
> Yes, fortunately things using embedded vec do not at all expect a c++
> container, and so don't really mismatch it.  You probably should not be
> creating them yourself unless you are creating a new object with an
> embedded vector, and you probably don't want to do that.
> 
>>>
>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>> make anything worse than it is.  (I have a project that depends on
>>>> a sane auto_vec working).
>>>
>>> So how does your usage look like?  I can't really figure who'd need
>>> deep copying of a container - note there's vec<>::copy at your
>>> discretion.
>>>
>>>> A couple of alternatives to solving this are to use std::vector or
>>>> write an equivalent vector class just for GCC.
> 
> imho one of the significant advantages to having our own datastructures
> rather than using the standard library is the ability to have a
> different API that is less constrained by history, and can make better
> choices than standard containers like deleting operators that would
> otherwise require deep coppies.  Though certainly they don't always live
> up to that like the oversight here of not defining the copy / assignment
> operators at all.  Perhaps there's an argument to be made for the
> standard containers doing deep coppies that it makes the language easier
> to use, but its not all that much easier than .copy(), if that's your
> priority c++ probably isn't the right tool for the job, and I doubt it
> makes sense for gcc in particular.

Having special containers just for GCC is mainly a liability.  They
are different, sometimes gratuitously, from the standard containers
that most C++ programmers are familiar with, and commonly even
inconsistent with one another.  Not just their APs but also their
guarantees and effects.  They're harder to use correctly and easy
to make mistakes with.  They're also less well tested and and much
less well documented.

>>> As said, can you show the usage that's impossible to do with
>>> the current vec<>/auto_vec<>?
>>
>> The test case in PR 90904 shows a trivial example.  More generally,
>> using an auto_vec that depends on it being assignable (e.g., storing
>> an auto_vec in another container like hash_map or auto_vec itself)
>> is impossible.  Using a plain vec requires manual memory management
>> and so is error-prone.
> 
> Certainly deleting the copy constructor and assignment operator means
> that you can't use them,  but can you show real code where it is a
> significant imposition to have to call .copy() rather than using them?
> Certainly its a little longer, but deep copies are a bit of a
> performance footgun, especially when you have vectors linear in the size
> of the function all over, and your goal is to be no worse than
> O(N log(N)), meaning you can copy the vector at most log(N) times at
> worst.
> 
> I would think storing move only objects in auto_vec and hash_* should
> work, and if it doesn't should be fixable without introducing overly
> easy ways to make deep coppies.
> 
>> But more important, as a C++ code base, GCC should follow the best
>> practices for the language.  Among the essential ones are using RAII
>> to manage resources and the Rule of Three (or Five in C++ 11): a class
>> that defines a dtor should also define a copy ctor and copy assignment
>> (and move ctor and move assignment in C++).
> 
> When discussing the rule of 3/5 at least
> https://en.cppreference.com/w/cpp/language/rule_of_three considers
> deleting the member to be a form of definition, see the part about non
> copiable members and deleting both copy constructor and assignment,

The Rule of Three was coined sometime in the early '90s, well before
C++ 11 where deleted function were introduced.  The original intent
was to emphasize that a class that defines one of the three special
member functions should almost certainly define all of them, to make
the basic operations safe.

The reason for the rule was that programmers commonly forgot to
define the full set and ended up setting a trap for users of their
classes who inadvertently came to make use of their shallow copy
semantics.   In his 2001 Dr. Dobb's article about the rule, Andy
Koenig shows a poster child for this mistake that looks like
a spitting image of auto_vec:
https://www.drdobbs.com/c-made-easier-the-rule-of-three/184401400#1

Despite its notoriety, the mistake is still common today, including
in GCC.  Not just in auto_vec, but also elsewhere, including
the recently added auto_string_vec, or hash_table, now "fixed"
by providing a copy ctor but deleting copy assignment.  Thanks
to that, hash-based containers are safely copyable but cannot
be assigned.

> in
> this case to make the class move only.  Strictly speaking, I suppose its
> true that an array of 10k items is copiable, but its also very likely
> something to be avoided if at all possible, and doesn't need to be made
> easy.

Inefficient copying should certainly be avoided, not just in GCC
but in all code.  But it's not (or should not be) a design goal of
a general purpose API to make copying difficult just because some
copies might be excessive.  APIs should be easy and safe to work
with first.  Efficiency comes second, and shouldn't come at
the expense of maintainability or safety.

Martin

> 
> Trev
> 
>>
>> Martin


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-07 22:17                   ` Martin Sebor
@ 2021-06-08  2:41                     ` Trevor Saunders
  0 siblings, 0 replies; 59+ messages in thread
From: Trevor Saunders @ 2021-06-08  2:41 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Richard Biener, Jonathan Wakely, gcc-patches

On Mon, Jun 07, 2021 at 04:17:09PM -0600, Martin Sebor wrote:
> On 6/3/21 2:29 AM, Trevor Saunders wrote:
> > On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> > > On 6/2/21 12:55 AM, Richard Biener wrote:
> > > > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > 
> > > > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > > > 
> > > > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > > > 
> > > > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > > > assignment operator.
> > > > > > > > > > > 
> > > > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > > > bootstrap
> > > > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > > > 
> > > > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > > > operators?
> > > > > > > > > 
> > > > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > > > 
> > > > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > > > around
> > > > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > > > is used - as "reference" to a vector)
> > > > > > > 
> > > > > > > The vec base classes are special: they have no ctors at all (because
> > > > > > > of their use in unions).  That's something we might have to live with
> > > > > > > but it's not a model to follow in ordinary containers.
> > > > > > 
> > > > > > I don't think we have to live with it anymore, now that we're writing
> > > > > > C++11.
> > > > > > 
> > > > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > > > This change fixes that oversight.
> > 
> > I've been away a while, but trying to get back into this, sorry.  It was
> > definitely an oversight to leave these undefined for the compiler to
> > provide a default definition of, but I agree with Richi, the better
> > thing to have done, or do now would be to mark them as deleted and make
> > auto_vec move only (with copy() for when you really need a deep copy.
> > > > > > > 
> > > > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > > > primary template (that's also missing it).  In addition, it adds
> > > > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > > > assignment as you prefer.
> > > > > > 
> > > > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > > > still do a shallow copy.  I think it's probably better to disable the
> > > > > > copy special members for auto_vec until we fix vec<>.
> > > > > 
> > > > > There are at least a couple of problems that get in the way of fixing
> > > > > all of vec to act like a well-behaved C++ container:
> > > > > 
> > > > > 1) The embedded vec has a trailing "flexible" array member with its
> > > > > instances having different size.  They're initialized by memset and
> > > > > copied by memcpy.  The class can't have copy ctors or assignments
> > > > > but it should disable/delete them instead.
> > > > > 
> > > > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > > > shallow copy semantics (not just as function arguments but also as
> > > > > members of other such POD classes).  This can be changed by providing
> > > > > copy and move ctors and assignment operators for it, and also for
> > > > > some of the classes in which it's a member and that are used with
> > > > > the same assumption.
> > > > > 
> > > > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > > > and tree-vect-patterns.c).
> > > > > 
> > > > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > > > be a big and tricky project.  Tricky because it involves using
> > > > > std::move in places where what's moved is subsequently still used.
> > > > > I can keep plugging away at it but it won't change the fact that
> > > > > the embedded and heap-based vecs have different requirements.
> > > > 
> > > > So you figured that neither vec<> nor auto_vec<> are a container like
> > > > std::vector.
> > > 
> > > That's obvious from glancing at their definitions.  I didn't go
> > > through the exercise to figure that out.
> > > 
> > > > 
> > > > I'm not sure it makes sense to try to make it so since obviously vec<>
> > > > was designed to match the actual needs of GCC.  auto_vec<> was added
> > > > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > > > to provide initial stack storage.
> > > 
> > > The goal was to see if the two vec instances could be made safer
> > > to use but taking advantage of C++ 11 features.  As I mentioned
> > > recently, creating a copy of a vec and modifying it changes it as
> > > well as the original (e.g., by changing a vec argument passed to
> > > it by value a function changes the actual argument in the caller).
> > > That's surprising to most C++ programmers.
> > 
> > It can probably be improved now with c++11, but while very unfortunate
> > There is hard requirements on how vec works from existing code using it.
> > 
> > > My conclusion from the exercise is that although some of the problems
> > > with vec can, and IMO should, be solved, making the heap-based one
> > > a well-behaved C++ 11 container will take considerable effort and
> > > is impossible for the embedded vec.
> > 
> > Yes, fortunately things using embedded vec do not at all expect a c++
> > container, and so don't really mismatch it.  You probably should not be
> > creating them yourself unless you are creating a new object with an
> > embedded vector, and you probably don't want to do that.
> > 
> > > > 
> > > > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > > > to be put on hold until the rats nest above is untangled.  It won't
> > > > > make anything worse than it is.  (I have a project that depends on
> > > > > a sane auto_vec working).
> > > > 
> > > > So how does your usage look like?  I can't really figure who'd need
> > > > deep copying of a container - note there's vec<>::copy at your
> > > > discretion.
> > > > 
> > > > > A couple of alternatives to solving this are to use std::vector or
> > > > > write an equivalent vector class just for GCC.
> > 
> > imho one of the significant advantages to having our own datastructures
> > rather than using the standard library is the ability to have a
> > different API that is less constrained by history, and can make better
> > choices than standard containers like deleting operators that would
> > otherwise require deep coppies.  Though certainly they don't always live
> > up to that like the oversight here of not defining the copy / assignment
> > operators at all.  Perhaps there's an argument to be made for the
> > standard containers doing deep coppies that it makes the language easier
> > to use, but its not all that much easier than .copy(), if that's your
> > priority c++ probably isn't the right tool for the job, and I doubt it
> > makes sense for gcc in particular.
> 
> Having special containers just for GCC is mainly a liability.  They
> are different, sometimes gratuitously, from the standard containers
> that most C++ programmers are familiar with, and commonly even
> inconsistent with one another.  Not just their APs but also their
> guarantees and effects.  They're harder to use correctly and easy
> to make mistakes with.  They're also less well tested and and much
> less well documented.

There's certainly room for improvement in gcc's datastructures.  However
improving them to behave sensibly often ends up taking significant work
since you have to hunt down all consumers who "abused" the previous API
and fix them.  I'm not sure C++ programmers are that familiar with the
standard library versions of things, most large projects I've worked
with have had there own internal versions, but I may be an outlier here.

> > > > As said, can you show the usage that's impossible to do with
> > > > the current vec<>/auto_vec<>?
> > > 
> > > The test case in PR 90904 shows a trivial example.  More generally,
> > > using an auto_vec that depends on it being assignable (e.g., storing
> > > an auto_vec in another container like hash_map or auto_vec itself)
> > > is impossible.  Using a plain vec requires manual memory management
> > > and so is error-prone.
> > 
> > Certainly deleting the copy constructor and assignment operator means
> > that you can't use them,  but can you show real code where it is a
> > significant imposition to have to call .copy() rather than using them?
> > Certainly its a little longer, but deep copies are a bit of a
> > performance footgun, especially when you have vectors linear in the size
> > of the function all over, and your goal is to be no worse than
> > O(N log(N)), meaning you can copy the vector at most log(N) times at
> > worst.
> > 
> > I would think storing move only objects in auto_vec and hash_* should
> > work, and if it doesn't should be fixable without introducing overly
> > easy ways to make deep coppies.
> > 
> > > But more important, as a C++ code base, GCC should follow the best
> > > practices for the language.  Among the essential ones are using RAII
> > > to manage resources and the Rule of Three (or Five in C++ 11): a class
> > > that defines a dtor should also define a copy ctor and copy assignment
> > > (and move ctor and move assignment in C++).
> > 
> > When discussing the rule of 3/5 at least
> > https://en.cppreference.com/w/cpp/language/rule_of_three considers
> > deleting the member to be a form of definition, see the part about non
> > copiable members and deleting both copy constructor and assignment,
> 
> The Rule of Three was coined sometime in the early '90s, well before
> C++ 11 where deleted function were introduced.  The original intent
> was to emphasize that a class that defines one of the three special
> member functions should almost certainly define all of them, to make
> the basic operations safe.
> 
> The reason for the rule was that programmers commonly forgot to
> define the full set and ended up setting a trap for users of their
> classes who inadvertently came to make use of their shallow copy
> semantics.   In his 2001 Dr. Dobb's article about the rule, Andy
> Koenig shows a poster child for this mistake that looks like
> a spitting image of auto_vec:
> https://www.drdobbs.com/c-made-easier-the-rule-of-three/184401400#1
> 
> Despite its notoriety, the mistake is still common today, including
> in GCC.  Not just in auto_vec, but also elsewhere, including
> the recently added auto_string_vec, or hash_table, now "fixed"
> by providing a copy ctor but deleting copy assignment.  Thanks
> to that, hash-based containers are safely copyable but cannot
> be assigned.

Well, its certainly unfortunate that copy construction and copy
assignment of hash tables is different, but personally I think that
should be resolved to have a copy() member function like vec, and only
allow move constructors/assignment.  I honestly can't think of a single
case where I wanted a copy of a hash table, I feel like it must have
come up at some point, but its pretty rare.  As for auto_vec I'd guess
it was just inattention on my part, but I suppose its possible there was
some reason it was necessary to be compatible with consumers.  I suppose
one question is if there is a warning we can enable to catch
future classes making these mistakes, I think it would need to accept
=default and =delete as definitions, but having to write those at least
should force you to consider the options.

> > in
> > this case to make the class move only.  Strictly speaking, I suppose its
> > true that an array of 10k items is copiable, but its also very likely
> > something to be avoided if at all possible, and doesn't need to be made
> > easy.
> 
> Inefficient copying should certainly be avoided, not just in GCC
> but in all code.  But it's not (or should not be) a design goal of
> a general purpose API to make copying difficult just because some
> copies might be excessive.  APIs should be easy and safe to work
> with first.  Efficiency comes second, and shouldn't come at
> the expense of maintainability or safety.

Well, efficiency is correctness, though its certainly harder to measure
than if the program crashes or not.  One advantage we have writing
things just for gcc is they are less general purpose than the standard
library, and don't need to concern themselves with things  like making
it easy to quickly write code that doesn't really care about efficiency
and desperately wishes to be python.  I don't really agree with it, but
I can see why designing the standard library assuming a green field you
might decide to make hash tables copiable, however that trade off is
somewhat different for gcc.  Its also important to consider that
understanding the runtime of code you read is part of making an API easy
to use, and if you need to do analysis to tell if something is a O(1) or
O(N) operation that's not exactly easy.  The even worse case is when
someone has to spend hours with perf to findwhere a object is coppied
needlessly, when a better API could have prompted the author to spend  a
few seconds thinking about what's needed and avoiding the bug in the
first place.

Trev

> 
> Martin
> 
> > 
> > Trev
> > 
> > > 
> > > Martin
> 

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-07 20:34                     ` Martin Sebor
@ 2021-06-08  3:26                       ` Trevor Saunders
  2021-06-08  7:19                         ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Trevor Saunders @ 2021-06-08  3:26 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Richard Biener, Jonathan Wakely, gcc-patches

On Mon, Jun 07, 2021 at 02:34:26PM -0600, Martin Sebor wrote:
> On 6/7/21 2:51 AM, Richard Biener wrote:
> > On Thu, Jun 3, 2021 at 10:29 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > > 
> > > On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> > > > On 6/2/21 12:55 AM, Richard Biener wrote:
> > > > > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > 
> > > > > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > > > > 
> > > > > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > > > > 
> > > > > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > > > > assignment operator.
> > > > > > > > > > > > 
> > > > > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > > > > bootstrap
> > > > > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > > > > 
> > > > > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > > > > operators?
> > > > > > > > > > 
> > > > > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > > > > 
> > > > > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > > > > around
> > > > > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > > > > is used - as "reference" to a vector)
> > > > > > > > 
> > > > > > > > The vec base classes are special: they have no ctors at all (because
> > > > > > > > of their use in unions).  That's something we might have to live with
> > > > > > > > but it's not a model to follow in ordinary containers.
> > > > > > > 
> > > > > > > I don't think we have to live with it anymore, now that we're writing
> > > > > > > C++11.
> > > > > > > 
> > > > > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > > > > This change fixes that oversight.
> > > 
> > > I've been away a while, but trying to get back into this, sorry.  It was
> > > definitely an oversight to leave these undefined for the compiler to
> > > provide a default definition of, but I agree with Richi, the better
> > > thing to have done, or do now would be to mark them as deleted and make
> > > auto_vec move only (with copy() for when you really need a deep copy.
> > > > > > > > 
> > > > > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > > > > primary template (that's also missing it).  In addition, it adds
> > > > > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > > > > assignment as you prefer.
> > > > > > > 
> > > > > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > > > > still do a shallow copy.  I think it's probably better to disable the
> > > > > > > copy special members for auto_vec until we fix vec<>.
> > > > > > 
> > > > > > There are at least a couple of problems that get in the way of fixing
> > > > > > all of vec to act like a well-behaved C++ container:
> > > > > > 
> > > > > > 1) The embedded vec has a trailing "flexible" array member with its
> > > > > > instances having different size.  They're initialized by memset and
> > > > > > copied by memcpy.  The class can't have copy ctors or assignments
> > > > > > but it should disable/delete them instead.
> > > > > > 
> > > > > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > > > > shallow copy semantics (not just as function arguments but also as
> > > > > > members of other such POD classes).  This can be changed by providing
> > > > > > copy and move ctors and assignment operators for it, and also for
> > > > > > some of the classes in which it's a member and that are used with
> > > > > > the same assumption.
> > > > > > 
> > > > > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > > > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > > > > and tree-vect-patterns.c).
> > > > > > 
> > > > > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > > > > be a big and tricky project.  Tricky because it involves using
> > > > > > std::move in places where what's moved is subsequently still used.
> > > > > > I can keep plugging away at it but it won't change the fact that
> > > > > > the embedded and heap-based vecs have different requirements.
> > > > > 
> > > > > So you figured that neither vec<> nor auto_vec<> are a container like
> > > > > std::vector.
> > > > 
> > > > That's obvious from glancing at their definitions.  I didn't go
> > > > through the exercise to figure that out.
> > > > 
> > > > > 
> > > > > I'm not sure it makes sense to try to make it so since obviously vec<>
> > > > > was designed to match the actual needs of GCC.  auto_vec<> was added
> > > > > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > > > > to provide initial stack storage.
> > > > 
> > > > The goal was to see if the two vec instances could be made safer
> > > > to use but taking advantage of C++ 11 features.  As I mentioned
> > > > recently, creating a copy of a vec and modifying it changes it as
> > > > well as the original (e.g., by changing a vec argument passed to
> > > > it by value a function changes the actual argument in the caller).
> > > > That's surprising to most C++ programmers.
> > > 
> > > It can probably be improved now with c++11, but while very unfortunate
> > > There is hard requirements on how vec works from existing code using it.
> > > 
> > > > My conclusion from the exercise is that although some of the problems
> > > > with vec can, and IMO should, be solved, making the heap-based one
> > > > a well-behaved C++ 11 container will take considerable effort and
> > > > is impossible for the embedded vec.
> > > 
> > > Yes, fortunately things using embedded vec do not at all expect a c++
> > > container, and so don't really mismatch it.  You probably should not be
> > > creating them yourself unless you are creating a new object with an
> > > embedded vector, and you probably don't want to do that.
> > > 
> > > > > 
> > > > > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > > > > to be put on hold until the rats nest above is untangled.  It won't
> > > > > > make anything worse than it is.  (I have a project that depends on
> > > > > > a sane auto_vec working).
> > > > > 
> > > > > So how does your usage look like?  I can't really figure who'd need
> > > > > deep copying of a container - note there's vec<>::copy at your
> > > > > discretion.
> > > > > 
> > > > > > A couple of alternatives to solving this are to use std::vector or
> > > > > > write an equivalent vector class just for GCC.
> > > 
> > > imho one of the significant advantages to having our own datastructures
> > > rather than using the standard library is the ability to have a
> > > different API that is less constrained by history, and can make better
> > > choices than standard containers like deleting operators that would
> > > otherwise require deep coppies.  Though certainly they don't always live
> > > up to that like the oversight here of not defining the copy / assignment
> > > operators at all.  Perhaps there's an argument to be made for the
> > > standard containers doing deep coppies that it makes the language easier
> > > to use, but its not all that much easier than .copy(), if that's your
> > > priority c++ probably isn't the right tool for the job, and I doubt it
> > > makes sense for gcc in particular.
> > > 
> > > > > As said, can you show the usage that's impossible to do with
> > > > > the current vec<>/auto_vec<>?
> > > > 
> > > > The test case in PR 90904 shows a trivial example.  More generally,
> > > > using an auto_vec that depends on it being assignable (e.g., storing
> > > > an auto_vec in another container like hash_map or auto_vec itself)
> > > > is impossible.  Using a plain vec requires manual memory management
> > > > and so is error-prone.
> > 
> > Btw, I remember once trying to make hash_map<int, auto_vec<int, 1> >
> > work which pre-dated C++11 allowance (but I found a much nicer,
> > albeit non-"C++" solution using obstacks and linked lists .. heh).  That
> > might work nowadays if we fix hash_map re-allocation to use
> > std::move and add move CTORs to the auto_vec<int, N> template
> > (I refrained from that when I added them to the , 0 specialization
> > since even moving would mean moving quite some storage).
> 
> hash_map relies on its elements being copy-assignable.  To avoid that
> it needs to overload its put() member to take an rvalue reference and
> forward the argument to the move ctor.  Those would be good changes
> to make but they alone wouldn't make using a hash_map easy to use
> with a move-only type because the move overload is only viable in
> limited contexts.  E.g., it wouldn't make this common use case valid:
> 
>   void f (hash_map<int, Moveable> &m, const Moveable &x)
>   {
>     m.put (1, x);
>   }
> 
> Sequences like vec (and auto_vec) rely on their elements having a copy
> ctor and copy assignment to grow by inserting elements in the middle.
> But similar to hash_map, using them also depends on being able to copy
> the elements (e.g., call v.push_back(x) in the above).

There's certainly work to do to make these types more than kinda sorta
work with move only types, or for that matter copyiable types.  I think
I've looked at a fair percentage of the vec consumers in gcc, and my
sense is most of them probably could move the object into the vector,
but most of the current ones are also storing trivially copiable data,
so that may not be fair.  That said I also reguard it as a good thing
that if you find yourself in a case like your f function above you need
to consider if you should make a copy or if there is a better way to
take ownership of the object and pass it to the vector, this is really
just forcing you to make an explicit decision about what should happen,
rather than leaving it to the compiler to decide.

> In general, move semantics are a special case, an optimization, of copy
> semantics.  There are use cases for moveable-only types but they're not
> the default and they limit the usability of those types.

While I suppose it in some sense is trivially true that a move is just a
copy and destruction of the original object, I think there's a real
semantic difference between copying the object and transfering ownership
of it to something else.  Consider Rust's choices in this area with
objects being default move only, and types with destructors only
implementing the clone trait not copy.  Certainly Rust and C++ are
different languages, but I think it works reasonably well for Rust, and
its generally a good way to think about C++ too, but then I think a lot
of the C++ that has any business being C++ should eventually become Rust
so milage may vary.

Trev



> 
> Martin
> 
> > 
> > > Certainly deleting the copy constructor and assignment operator means
> > > that you can't use them,  but can you show real code where it is a
> > > significant imposition to have to call .copy() rather than using them?
> > > Certainly its a little longer, but deep copies are a bit of a
> > > performance footgun, especially when you have vectors linear in the size
> > > of the function all over, and your goal is to be no worse than
> > > O(N log(N)), meaning you can copy the vector at most log(N) times at
> > > worst.
> > > 
> > > I would think storing move only objects in auto_vec and hash_* should
> > > work, and if it doesn't should be fixable without introducing overly
> > > easy ways to make deep coppies.
> > > 
> > > > But more important, as a C++ code base, GCC should follow the best
> > > > practices for the language.  Among the essential ones are using RAII
> > > > to manage resources and the Rule of Three (or Five in C++ 11): a class
> > > > that defines a dtor should also define a copy ctor and copy assignment
> > > > (and move ctor and move assignment in C++).
> > > 
> > > When discussing the rule of 3/5 at least
> > > https://en.cppreference.com/w/cpp/language/rule_of_three considers
> > > deleting the member to be a form of definition, see the part about non
> > > copiable members and deleting both copy constructor and assignment, in
> > > this case to make the class move only.  Strictly speaking, I suppose its
> > > true that an array of 10k items is copiable, but its also very likely
> > > something to be avoided if at all possible, and doesn't need to be made
> > > easy.
> > > 
> > > Trev
> > > 
> > > > 
> > > > Martin
> 

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-08  3:26                       ` Trevor Saunders
@ 2021-06-08  7:19                         ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2021-06-08  7:19 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Martin Sebor, Jonathan Wakely, gcc-patches

On Tue, Jun 8, 2021 at 5:26 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
>
> On Mon, Jun 07, 2021 at 02:34:26PM -0600, Martin Sebor wrote:
> > On 6/7/21 2:51 AM, Richard Biener wrote:
> > > On Thu, Jun 3, 2021 at 10:29 AM Trevor Saunders <tbsaunde@tbsaunde.org> wrote:
> > > >
> > > > On Wed, Jun 02, 2021 at 10:04:03AM -0600, Martin Sebor via Gcc-patches wrote:
> > > > > On 6/2/21 12:55 AM, Richard Biener wrote:
> > > > > > On Tue, Jun 1, 2021 at 9:56 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > >
> > > > > > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > > > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > > > > >
> > > > > > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > > > > >
> > > > > > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > > > > > assignment operator.
> > > > > > > > > > > > >
> > > > > > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > > > > > with a few simple tests.  It makes auto_vec safe to use in containers
> > > > > > > > > > > > > that expect copyable and assignable element types and passes
> > > > > > > > > > > > > bootstrap
> > > > > > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > > > > >
> > > > > > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > > > > > can be quite inefficient?  Thus the option is to delete those
> > > > > > > > > > > > operators?
> > > > > > > > > > >
> > > > > > > > > > > I would strongly prefer the generic vector class to have the properties
> > > > > > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > > > > > we also want another vector type with this restriction I suggest to add
> > > > > > > > > > > another "noncopyable" type and make that property explicit in its name.
> > > > > > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > > > > >
> > > > > > > > > > I'm not sure (and not strictly against the copy and assign).  Looking
> > > > > > > > > > around
> > > > > > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > > > > > is used - as "reference" to a vector)
> > > > > > > > >
> > > > > > > > > The vec base classes are special: they have no ctors at all (because
> > > > > > > > > of their use in unions).  That's something we might have to live with
> > > > > > > > > but it's not a model to follow in ordinary containers.
> > > > > > > >
> > > > > > > > I don't think we have to live with it anymore, now that we're writing
> > > > > > > > C++11.
> > > > > > > >
> > > > > > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > > > > > This change fixes that oversight.
> > > >
> > > > I've been away a while, but trying to get back into this, sorry.  It was
> > > > definitely an oversight to leave these undefined for the compiler to
> > > > provide a default definition of, but I agree with Richi, the better
> > > > thing to have done, or do now would be to mark them as deleted and make
> > > > auto_vec move only (with copy() for when you really need a deep copy.
> > > > > > > > >
> > > > > > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > > > > > primary template (that's also missing it).  In addition, it adds
> > > > > > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > > > > > assignment as you prefer.
> > > > > > > >
> > > > > > > > Hmm, adding another class doesn't really help with the confusion richi
> > > > > > > > mentions.  And many uses of auto_vec will pass them as vec, which will
> > > > > > > > still do a shallow copy.  I think it's probably better to disable the
> > > > > > > > copy special members for auto_vec until we fix vec<>.
> > > > > > >
> > > > > > > There are at least a couple of problems that get in the way of fixing
> > > > > > > all of vec to act like a well-behaved C++ container:
> > > > > > >
> > > > > > > 1) The embedded vec has a trailing "flexible" array member with its
> > > > > > > instances having different size.  They're initialized by memset and
> > > > > > > copied by memcpy.  The class can't have copy ctors or assignments
> > > > > > > but it should disable/delete them instead.
> > > > > > >
> > > > > > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > > > > > shallow copy semantics (not just as function arguments but also as
> > > > > > > members of other such POD classes).  This can be changed by providing
> > > > > > > copy and move ctors and assignment operators for it, and also for
> > > > > > > some of the classes in which it's a member and that are used with
> > > > > > > the same assumption.
> > > > > > >
> > > > > > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > > > > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > > > > > and tree-vect-patterns.c).
> > > > > > >
> > > > > > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > > > > > be a big and tricky project.  Tricky because it involves using
> > > > > > > std::move in places where what's moved is subsequently still used.
> > > > > > > I can keep plugging away at it but it won't change the fact that
> > > > > > > the embedded and heap-based vecs have different requirements.
> > > > > >
> > > > > > So you figured that neither vec<> nor auto_vec<> are a container like
> > > > > > std::vector.
> > > > >
> > > > > That's obvious from glancing at their definitions.  I didn't go
> > > > > through the exercise to figure that out.
> > > > >
> > > > > >
> > > > > > I'm not sure it makes sense to try to make it so since obviously vec<>
> > > > > > was designed to match the actual needs of GCC.  auto_vec<> was added
> > > > > > to make a RAII (like auto_bitmap, etc.) wrapper, plus it got the ability
> > > > > > to provide initial stack storage.
> > > > >
> > > > > The goal was to see if the two vec instances could be made safer
> > > > > to use but taking advantage of C++ 11 features.  As I mentioned
> > > > > recently, creating a copy of a vec and modifying it changes it as
> > > > > well as the original (e.g., by changing a vec argument passed to
> > > > > it by value a function changes the actual argument in the caller).
> > > > > That's surprising to most C++ programmers.
> > > >
> > > > It can probably be improved now with c++11, but while very unfortunate
> > > > There is hard requirements on how vec works from existing code using it.
> > > >
> > > > > My conclusion from the exercise is that although some of the problems
> > > > > with vec can, and IMO should, be solved, making the heap-based one
> > > > > a well-behaved C++ 11 container will take considerable effort and
> > > > > is impossible for the embedded vec.
> > > >
> > > > Yes, fortunately things using embedded vec do not at all expect a c++
> > > > container, and so don't really mismatch it.  You probably should not be
> > > > creating them yourself unless you are creating a new object with an
> > > > embedded vector, and you probably don't want to do that.
> > > >
> > > > > >
> > > > > > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > > > > > to be put on hold until the rats nest above is untangled.  It won't
> > > > > > > make anything worse than it is.  (I have a project that depends on
> > > > > > > a sane auto_vec working).
> > > > > >
> > > > > > So how does your usage look like?  I can't really figure who'd need
> > > > > > deep copying of a container - note there's vec<>::copy at your
> > > > > > discretion.
> > > > > >
> > > > > > > A couple of alternatives to solving this are to use std::vector or
> > > > > > > write an equivalent vector class just for GCC.
> > > >
> > > > imho one of the significant advantages to having our own datastructures
> > > > rather than using the standard library is the ability to have a
> > > > different API that is less constrained by history, and can make better
> > > > choices than standard containers like deleting operators that would
> > > > otherwise require deep coppies.  Though certainly they don't always live
> > > > up to that like the oversight here of not defining the copy / assignment
> > > > operators at all.  Perhaps there's an argument to be made for the
> > > > standard containers doing deep coppies that it makes the language easier
> > > > to use, but its not all that much easier than .copy(), if that's your
> > > > priority c++ probably isn't the right tool for the job, and I doubt it
> > > > makes sense for gcc in particular.
> > > >
> > > > > > As said, can you show the usage that's impossible to do with
> > > > > > the current vec<>/auto_vec<>?
> > > > >
> > > > > The test case in PR 90904 shows a trivial example.  More generally,
> > > > > using an auto_vec that depends on it being assignable (e.g., storing
> > > > > an auto_vec in another container like hash_map or auto_vec itself)
> > > > > is impossible.  Using a plain vec requires manual memory management
> > > > > and so is error-prone.
> > >
> > > Btw, I remember once trying to make hash_map<int, auto_vec<int, 1> >
> > > work which pre-dated C++11 allowance (but I found a much nicer,
> > > albeit non-"C++" solution using obstacks and linked lists .. heh).  That
> > > might work nowadays if we fix hash_map re-allocation to use
> > > std::move and add move CTORs to the auto_vec<int, N> template
> > > (I refrained from that when I added them to the , 0 specialization
> > > since even moving would mean moving quite some storage).
> >
> > hash_map relies on its elements being copy-assignable.  To avoid that
> > it needs to overload its put() member to take an rvalue reference and
> > forward the argument to the move ctor.  Those would be good changes
> > to make but they alone wouldn't make using a hash_map easy to use
> > with a move-only type because the move overload is only viable in
> > limited contexts.  E.g., it wouldn't make this common use case valid:
> >
> >   void f (hash_map<int, Moveable> &m, const Moveable &x)
> >   {
> >     m.put (1, x);
> >   }
> >
> > Sequences like vec (and auto_vec) rely on their elements having a copy
> > ctor and copy assignment to grow by inserting elements in the middle.
> > But similar to hash_map, using them also depends on being able to copy
> > the elements (e.g., call v.push_back(x) in the above).
>
> There's certainly work to do to make these types more than kinda sorta
> work with move only types, or for that matter copyiable types.  I think
> I've looked at a fair percentage of the vec consumers in gcc, and my
> sense is most of them probably could move the object into the vector,
> but most of the current ones are also storing trivially copiable data,
> so that may not be fair.  That said I also reguard it as a good thing
> that if you find yourself in a case like your f function above you need
> to consider if you should make a copy or if there is a better way to
> take ownership of the object and pass it to the vector, this is really
> just forcing you to make an explicit decision about what should happen,
> rather than leaving it to the compiler to decide.
>
> > In general, move semantics are a special case, an optimization, of copy
> > semantics.  There are use cases for moveable-only types but they're not
> > the default and they limit the usability of those types.
>
> While I suppose it in some sense is trivially true that a move is just a
> copy and destruction of the original object, I think there's a real
> semantic difference between copying the object and transfering ownership
> of it to something else.  Consider Rust's choices in this area with
> objects being default move only, and types with destructors only
> implementing the clone trait not copy.  Certainly Rust and C++ are
> different languages, but I think it works reasonably well for Rust, and
> its generally a good way to think about C++ too, but then I think a lot
> of the C++ that has any business being C++ should eventually become Rust
> so milage may vary.

I suppose some of the "confusion" around auto_vec and friends  (auto_vec
in particular) could have been avoided if we'd done auto<vec<..> > instead
and thus added a smart instance (not pointer) wrapper template that
deals with the RAII we wanted to add.  We definitely didn't want to make
vec<> a [lib]C++ style container - at least that was my understanding.

And yes, a large part of why we have custom data structures in GCC is
memory and time complexity of algorithms we use - what's usually
inefficient should simply be not available (without pain).

So at this point I'd support sprinkling the missing = deleted; copy/assign
methods around our containers.

Richard.

> Trev
>
>
>
> >
> > Martin
> >
> > >
> > > > Certainly deleting the copy constructor and assignment operator means
> > > > that you can't use them,  but can you show real code where it is a
> > > > significant imposition to have to call .copy() rather than using them?
> > > > Certainly its a little longer, but deep copies are a bit of a
> > > > performance footgun, especially when you have vectors linear in the size
> > > > of the function all over, and your goal is to be no worse than
> > > > O(N log(N)), meaning you can copy the vector at most log(N) times at
> > > > worst.
> > > >
> > > > I would think storing move only objects in auto_vec and hash_* should
> > > > work, and if it doesn't should be fixable without introducing overly
> > > > easy ways to make deep coppies.
> > > >
> > > > > But more important, as a C++ code base, GCC should follow the best
> > > > > practices for the language.  Among the essential ones are using RAII
> > > > > to manage resources and the Rule of Three (or Five in C++ 11): a class
> > > > > that defines a dtor should also define a copy ctor and copy assignment
> > > > > (and move ctor and move assignment in C++).
> > > >
> > > > When discussing the rule of 3/5 at least
> > > > https://en.cppreference.com/w/cpp/language/rule_of_three considers
> > > > deleting the member to be a form of definition, see the part about non
> > > > copiable members and deleting both copy constructor and assignment, in
> > > > this case to make the class move only.  Strictly speaking, I suppose its
> > > > true that an array of 10k items is copiable, but its also very likely
> > > > something to be avoided if at all possible, and doesn't need to be made
> > > > easy.
> > > >
> > > > Trev
> > > >
> > > > >
> > > > > Martin
> >

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-01 21:38             ` Jason Merrill
@ 2021-06-25 20:51               ` Martin Sebor
  2021-06-25 22:11                 ` Jason Merrill
                                   ` (2 more replies)
  0 siblings, 3 replies; 59+ messages in thread
From: Martin Sebor @ 2021-06-25 20:51 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 7090 bytes --]

On 6/1/21 3:38 PM, Jason Merrill wrote:
> On 6/1/21 3:56 PM, Martin Sebor wrote:
>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>
>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>
>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>> assignment operator.
>>>>>>>>
>>>>>>>> The attached patch adds the two special functions to auto_vec along
>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in 
>>>>>>>> containers
>>>>>>>> that expect copyable and assignable element types and passes 
>>>>>>>> bootstrap
>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>
>>>>>>> The question is whether we want such uses to appear since those
>>>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>>>> operators?
>>>>>>
>>>>>> I would strongly prefer the generic vector class to have the 
>>>>>> properties
>>>>>> expected of any other generic container: copyable and assignable.  If
>>>>>> we also want another vector type with this restriction I suggest 
>>>>>> to add
>>>>>> another "noncopyable" type and make that property explicit in its 
>>>>>> name.
>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>
>>>>> I'm not sure (and not strictly against the copy and assign). 
>>>>> Looking around
>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>> might be surprising (I added the move capability to match how vec<>
>>>>> is used - as "reference" to a vector)
>>>>
>>>> The vec base classes are special: they have no ctors at all (because
>>>> of their use in unions).  That's something we might have to live with
>>>> but it's not a model to follow in ordinary containers.
>>>
>>> I don't think we have to live with it anymore, now that we're writing 
>>> C++11.
>>>
>>>> The auto_vec class was introduced to fill the need for a conventional
>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>> assignment operators were an oversight, not a deliberate feature.
>>>> This change fixes that oversight.
>>>>
>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>> primary template (that's also missing it).  In addition, it adds
>>>> a new class called auto_vec_ncopy that disables copying and
>>>> assignment as you prefer.
>>>
>>> Hmm, adding another class doesn't really help with the confusion 
>>> richi mentions.  And many uses of auto_vec will pass them as vec, 
>>> which will still do a shallow copy.  I think it's probably better to 
>>> disable the copy special members for auto_vec until we fix vec<>.
>>
>> There are at least a couple of problems that get in the way of fixing
>> all of vec to act like a well-behaved C++ container:
>>
>> 1) The embedded vec has a trailing "flexible" array member with its
>> instances having different size.  They're initialized by memset and
>> copied by memcpy.  The class can't have copy ctors or assignments
>> but it should disable/delete them instead.
>>
>> 2) The heap-based vec is used throughout GCC with the assumption of
>> shallow copy semantics (not just as function arguments but also as
>> members of other such POD classes).  This can be changed by providing
>> copy and move ctors and assignment operators for it, and also for
>> some of the classes in which it's a member and that are used with
>> the same assumption.
>>
>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>> and tree-vect-patterns.c).
>>
>> I took a stab at both and while (1) is easy, (2) is shaping up to
>> be a big and tricky project.  Tricky because it involves using
>> std::move in places where what's moved is subsequently still used.
>> I can keep plugging away at it but it won't change the fact that
>> the embedded and heap-based vecs have different requirements.
>>
>> It doesn't seem to me that having a safely copyable auto_vec needs
>> to be put on hold until the rats nest above is untangled.  It won't
>> make anything worse than it is.  (I have a project that depends on
>> a sane auto_vec working).
>>
>> A couple of alternatives to solving this are to use std::vector or
>> write an equivalent vector class just for GCC.
> 
> It occurs to me that another way to work around the issue of passing an 
> auto_vec by value as a vec, and thus doing a shallow copy, would be to 
> add a vec ctor taking an auto_vec, and delete that.  This would mean if 
> you want to pass an auto_vec to a vec interface, it needs to be by 
> reference.  We might as well do the same for operator=, though that 
> isn't as important.

Thanks, that sounds like a good idea.  Attached is an implementation
of this change.  Since the auto_vec copy ctor and assignment have
been deleted by someone else in the interim, this patch doesn't
reverse that.  I will propose it separately after these changes
are finalized.

My approach was to 1) disable the auto_vec to vec conversion,
2) introduce an auto_vec::to_vec() to make the conversion possible
explicitly, and 3) resolve compilation errors by either changing
APIs to take a vec by reference or callers to convert auto_vec to
vec explicitly by to_vec().  In (3) I tried to minimize churn while
improving the const-correctness of the APIs.

When changing a vec API from by-value to by-reference I used vec &
and didn't try to use vec * even though the latter seems to be more
common (I avoided this to minimize the scope of changes).  If we
want to do this I suggest handling that in a separate change.

It's possible to get rid of vNULL in initialization.  It can be
replaced with value-initialization in declarations but it's still
handy when passing "empty" AKA nil vecs as arguments.  I didn't
do it except in one instance (vec::copy) as a POC.

I only touched APIs that needed to be adjusted so there may still
be others that take vec by value that didn't change because they're
not passed an auto_vec.  My hope is that we'll all pitch in and
convert those over time.

I kept an eye on the indirection due to changing vec to vec & that
Richi's concerned about but I didn't look into the cost in any
depth.  I don't have the sense that it's a significant issue.  In
small static functions it shouldn't matter if they get inlined and
in bigger ones I'd expect the cost of the indirection to be
outweighed by other costs.  If there are cases where it should
be felt to be significant I'll adjust those if you point thm out
to me.

Tested on x86_64-linux.

Martin

[-- Attachment #2: gcc-auto_vec-no-convert.diff --]
[-- Type: text/x-patch, Size: 67393 bytes --]

Disable implicit conversion from auto_vec to vec.


	* c-common.c (c_build_shufflevector): Adjust to vec change.
	* c-common.h (c_build_shufflevector): Same.

gcc/c/ChangeLog:

	* c-parser.c (c_finish_omp_declare_simd): Adjust to vec change.
	(c_parser_omp_declare_simd): Same.
	* c-tree.h (c_build_function_call_vec): Same.
	* c-typeck.c (c_build_function_call_vec): Same.

gcc/ChangeLog:

	* cfgloop.h (single_likely_exit): Adjust to vec change.
	* cfgloopanal.c (single_likely_exit): Same.
	* cgraph.h (struct cgraph_node): Same.
	* cgraphclones.c (cgraph_node::create_virtual_clone): Same.
	* dominance.c (prune_bbs_to_update_dominators): Same.
	(iterate_fix_dominators): Same.
	* dominance.h (iterate_fix_dominators): Same.
	* genautomata.c (merge_states): Same.
	* genextract.c (VEC_char_to_string): Same.
	* genmatch.c (dt_node::gen_kids_1): Same.
	(walk_captures): Same.
	* gimple-ssa-store-merging.c (check_no_overlap): Same.
	* gimple.c (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* gimple.h (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* haifa-sched.c (calc_priorities): Same.
	(haifa_sched_init): Same.
	(sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* ipa-cp.c (ipa_get_indirect_edge_target_1): Same.
	(adjust_callers_for_value_intersection): Same.
	(find_more_scalar_values_for_callers_subset): Same.
	(find_more_contexts_for_caller_subset): Same.
	(find_aggregate_values_for_callers_subset): Same.
	(copy_useful_known_contexts): Same.
	* ipa-fnsummary.c (remap_edge_summaries): Same.
	(remap_freqcounting_predicate): Same.
	* ipa-inline.c (add_new_edges_to_heap): Same.
	* ipa-predicate.c (predicate::remap_after_inlining): Same.
	* ipa-predicate.h:
	* ipa-prop.c (ipa_find_agg_cst_for_param): Same.
	* ipa-prop.h (ipa_find_agg_cst_for_param): Same.
	* ira-build.c (ira_loop_tree_body_rev_postorder): Same.
	* read-rtl.c (apply_iterators): Same.
	* rtl.h (native_decode_rtx): Same.
	(native_decode_vector_rtx): Same.
	* sched-int.h (sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* simplify-rtx.c (native_decode_vector_rtx): Same.
	(native_decode_rtx): Same.
	* tree-call-cdce.c (gen_shrink_wrap_conditions): Same.
	(shrink_wrap_one_built_in_call_with_conds): Same.
	(shrink_wrap_conditional_dead_built_in_calls): Same.
	* tree-data-ref.c (create_runtime_alias_checks): Same.
	(compute_all_dependences): Same.
	* tree-data-ref.h (compute_all_dependences): Same.
	(create_runtime_alias_checks): Same.
	(index_in_loop_nest): Same.
	* tree-if-conv.c (mask_exists): Same.
	* tree-loop-distribution.c (class loop_distribution): Same.
	(loop_distribution::create_rdg_vertices): Same.
	(dump_rdg_partitions): Same.
	(debug_rdg_partitions): Same.
	(partition_contains_all_rw): Same.
	(loop_distribution::distribute_loop): Same.
	* tree-parloops.c (oacc_entry_exit_ok_1): Same.
	(oacc_entry_exit_single_gang): Same.
	* tree-ssa-loop-im.c (hoist_memory_references): Same.
	(loop_suitable_for_sm): Same.
	* tree-ssa-loop-niter.c (bound_index): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (update_ops): Same.
	(swap_ops_for_binary_stmt): Same.
	(rewrite_expr_tree): Same.
	(rewrite_expr_tree_parallel): Same.
	* tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-sccvn.h (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-structalias.c (process_all_all_constraints): Same.
	(make_constraints_to): Same.
	(find_func_aliases_for_call): Same.
	(sort_fieldstack): Same.
	(check_for_overlaps): Same.
	* tree-vect-data-refs.c (vect_check_nonzero_value): Same.
	(vect_enhance_data_refs_alignment): Same.
	(vect_check_lower_bound): Same.
	(vect_prune_runtime_alias_test_list): Same.
	(vect_permute_store_chain): Same.
	* tree-vect-loop-manip.c (vect_create_cond_for_align_checks): Same.
	(vect_create_cond_for_unequal_addrs): Same.
	(vect_create_cond_for_lower_bounds): Same.
	(vect_create_cond_for_alias_checks): Same.
	* tree-vect-slp-patterns.c (vect_normalize_conj_loc): Same.
	(vect_validate_multiplication): Same.
	* tree-vect-slp.c (vect_analyze_slp_instance): Same.
	(vect_make_slp_decision): Same.
	(vect_slp_bbs): Same.
	(duplicate_and_interleave): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	* tree-vect-stmts.c (vect_create_vectorized_demotion_stmts): Same.
	* tree-vectorizer.h (vect_permute_store_chain): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	(duplicate_and_interleave): Same.
	* tree.c (build_vector_from_ctor): Same.
	(build_vector): Same.
	(check_vector_cst): Same.
	(check_vector_cst_duplicate): Same.
	(check_vector_cst_fill): Same.
	(check_vector_cst_stepped): Same.
	* tree.h (build_vector_from_ctor): Same.
	* vec.c (test_init): New.
	(vec_c_tests): Call test_init.
	* vec.h (struct vnull): Simplify.
	(auto_vec::to_vec): New member function.
	(vl_ptr>::copy): Use value initialization.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index c4eb2b1c920..9841a320f89 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1115,8 +1115,8 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask,
    and have vector types, V0 has the same element type as V1, and the
    number of elements the result is that of MASK.  */
 tree
-c_build_shufflevector (location_t loc, tree v0, tree v1, vec<tree> mask,
-		       bool complain)
+c_build_shufflevector (location_t loc, tree v0, tree v1,
+		       const vec<tree> &mask, bool complain)
 {
   tree ret;
   bool wrap = true;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 88022d0b0a9..e43b12ae1dc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1049,7 +1049,7 @@ extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
 extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note);
 extern tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true);
 extern tree c_build_shufflevector (location_t, tree, tree,
-				   vec<tree>, bool = true);
+				   const vec<tree> &, bool = true);
 extern tree c_build_vec_convert (location_t, tree, location_t, tree, bool = true);
 
 extern void init_c_lex (void);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 27034f88f49..e4a85eeb817 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1780,7 +1780,7 @@ c_parser_external_declaration (c_parser *parser)
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> &);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -20325,12 +20325,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, clauses.to_vec ());
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, clauses.to_vec ());
       break;
     case pragma_struct:
     case pragma_param:
@@ -20351,7 +20351,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, clauses.to_vec ());
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20360,7 +20360,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, clauses.to_vec ());
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20841,7 +20841,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> &clauses)
 {
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a671a3eb740..ab6db3860f5 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -759,8 +759,9 @@ extern tree c_finish_omp_clauses (tree, enum c_omp_region_type);
 extern tree c_build_va_arg (location_t, tree, location_t, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
-extern tree c_build_function_call_vec (location_t, vec<location_t>, tree,
-				       vec<tree, va_gc> *, vec<tree, va_gc> *);
+extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
+				       tree, vec<tree, va_gc> *,
+				       vec<tree, va_gc> *);
 extern tree c_omp_clause_copy_ctor (tree, tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d079ce4b05b..efd4810b901 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3243,7 +3243,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 /* Like build_function_call_vec, but call also resolve_overloaded_builtin.  */
 
 tree
-c_build_function_call_vec (location_t loc, vec<location_t> arg_loc,
+c_build_function_call_vec (location_t loc, const vec<location_t> &arg_loc,
 			   tree function, vec<tree, va_gc> *params,
 			   vec<tree, va_gc> *origtypes)
 {
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 5e699276c88..5c2b98db9e5 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -385,7 +385,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
 
 extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
 extern edge single_exit (const class loop *);
-extern edge single_likely_exit (class loop *loop, vec<edge>);
+extern edge single_likely_exit (class loop *loop, const vec<edge> &);
 extern unsigned num_loop_branches (const class loop *);
 
 extern edge loop_preheader_edge (const class loop *);
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index 2db46c81036..4cd73c29776 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -470,7 +470,7 @@ mark_loop_exit_edges (void)
    to noreturn call.  */
 
 edge
-single_likely_exit (class loop *loop, vec<edge> exits)
+single_likely_exit (class loop *loop, const vec<edge> &exits)
 {
   edge found = single_exit (loop);
   unsigned i;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 9f4338fdf87..8c776d6f3a8 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -949,7 +949,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
   /* Create callgraph node clone with new declaration.  The actual body will be
      copied later at compilation stage.  The name of the new clone will be
      constructed from the name of the original node, SUFFIX and NUM_SUFFIX.  */
-  cgraph_node *create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+  cgraph_node *create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				     vec<ipa_replace_map *, va_gc> *tree_map,
 				     ipa_param_adjustments *param_adjustments,
 				     const char * suffix, unsigned num_suffix);
diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index 9f86463b42d..125f1b92862 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -567,7 +567,7 @@ clone_function_name (tree decl, const char *suffix)
    bitmap interface.
    */
 cgraph_node *
-cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+cgraph_node::create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				   vec<ipa_replace_map *, va_gc> *tree_map,
 				   ipa_param_adjustments *param_adjustments,
 				   const char * suffix, unsigned num_suffix)
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/genautomata.c b/gcc/genautomata.c
index 6bbfc684afa..e488c5f28ef 100644
--- a/gcc/genautomata.c
+++ b/gcc/genautomata.c
@@ -6137,7 +6137,7 @@ evaluate_equiv_classes (automaton_t automaton, vec<state_t> *equiv_classes)
 
 /* The function merges equivalent states of AUTOMATON.  */
 static void
-merge_states (automaton_t automaton, vec<state_t> equiv_classes)
+merge_states (automaton_t automaton, const vec<state_t> &equiv_classes)
 {
   state_t curr_state;
   state_t new_state;
diff --git a/gcc/genextract.c b/gcc/genextract.c
index 6fe4a2524fc..3ed2f6846c9 100644
--- a/gcc/genextract.c
+++ b/gcc/genextract.c
@@ -214,7 +214,7 @@ VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
    to a NUL-terminated string in malloc memory.  */
 static char *
-VEC_char_to_string (vec<char> v)
+VEC_char_to_string (const vec<char> &v)
 {
   size_t n = v.length ();
   char *s = XNEWVEC (char, n + 1);
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 4d476720c9e..dfd793d1f9b 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1628,8 +1628,9 @@ public:
 
   void gen_kids (FILE *, int, bool, int);
   void gen_kids_1 (FILE *, int, bool, int,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_operand *>,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_node *>);
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_node *> &);
 
   void analyze (sinfo_map_t &);
 };
@@ -2979,12 +2980,12 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
 
 void
 dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
-		     vec<dt_operand *> gimple_exprs,
-		     vec<dt_operand *> generic_exprs,
-		     vec<dt_operand *> fns,
-		     vec<dt_operand *> generic_fns,
-		     vec<dt_operand *> preds,
-		     vec<dt_node *> others)
+		     const vec<dt_operand *> &gimple_exprs,
+		     const vec<dt_operand *> &generic_exprs,
+		     const vec<dt_operand *> &fns,
+		     const vec<dt_operand *> &generic_fns,
+		     const vec<dt_operand *> &preds,
+		     const vec<dt_node *> &others)
 {
   char buf[128];
   char *kid_opname = buf;
@@ -5027,7 +5028,7 @@ parser::parse_pattern ()
    recursively.  */
 
 static void
-walk_captures (operand *op, vec<vec<capture *> > cpts)
+walk_captures (operand *op, vec<vec<capture *> > &cpts)
 {
   if (! op)
     return;
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 632947950e4..02ce068d9cf 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -2654,7 +2654,8 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
    go after the = _5 store and thus change behavior.  */
 
 static bool
-check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
+check_no_overlap (const vec<store_immediate_info *> &m_store_info,
+		  unsigned int i,
 		  bool all_integer_cst_p, unsigned int first_order,
 		  unsigned int last_order, unsigned HOST_WIDE_INT start,
 		  unsigned HOST_WIDE_INT end, unsigned int first_earlier,
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f1044e9c630..108daeda43b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -241,7 +241,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_vec (tree fn, vec<tree> args)
+gimple_build_call_vec (tree fn, const vec<tree> &args)
 {
   unsigned i;
   unsigned nargs = args.length ();
@@ -338,7 +338,7 @@ gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args)
+gimple_build_call_internal_vec (enum internal_fn fn, const vec<tree> &args)
 {
   unsigned i, nargs;
   gcall *call;
@@ -802,7 +802,7 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
    ARGS is a vector of labels excluding the default.  */
 
 gswitch *
-gimple_build_switch (tree index, tree default_label, vec<tree> args)
+gimple_build_switch (tree index, tree default_label, const vec<tree> &args)
 {
   unsigned i, nlabels = args.length ();
 
@@ -3049,7 +3049,7 @@ compare_case_labels (const void *p1, const void *p2)
 /* Sort the case labels in LABEL_VEC in place in ascending order.  */
 
 void
-sort_case_labels (vec<tree> label_vec)
+sort_case_labels (vec<tree> &label_vec)
 {
   label_vec.qsort (compare_case_labels);
 }
@@ -3074,7 +3074,7 @@ sort_case_labels (vec<tree> label_vec)
    found or not.  */
 
 void
-preprocess_case_label_vec_for_gimple (vec<tree> labels,
+preprocess_case_label_vec_for_gimple (vec<tree> &labels,
 				      tree index_type,
 				      tree *default_casep)
 {
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e7dc2a45a13..aabf68eaea0 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1516,11 +1516,11 @@ void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
-gcall *gimple_build_call_vec (tree, vec<tree> );
+gcall *gimple_build_call_vec (tree, const vec<tree> &);
 gcall *gimple_build_call (tree, unsigned, ...);
 gcall *gimple_build_call_valist (tree, unsigned, va_list);
 gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
-gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
+gcall *gimple_build_call_internal_vec (enum internal_fn, const vec<tree> &);
 gcall *gimple_build_call_from_tree (tree, tree);
 gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
@@ -1547,7 +1547,7 @@ gtry *gimple_build_try (gimple_seq, gimple_seq,
 gimple *gimple_build_wce (gimple_seq);
 gresx *gimple_build_resx (int);
 gswitch *gimple_build_switch_nlabels (unsigned, tree, tree);
-gswitch *gimple_build_switch (tree, tree, vec<tree> );
+gswitch *gimple_build_switch (tree, tree, const vec<tree> &);
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
@@ -1626,8 +1626,8 @@ extern bool nonbarrier_call_p (gimple *);
 extern bool infer_nonnull_range (gimple *, tree);
 extern bool infer_nonnull_range_by_dereference (gimple *, tree);
 extern bool infer_nonnull_range_by_attribute (gimple *, tree);
-extern void sort_case_labels (vec<tree>);
-extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
+extern void sort_case_labels (vec<tree> &);
+extern void preprocess_case_label_vec_for_gimple (vec<tree> &, tree, tree *);
 extern void gimple_seq_set_location (gimple_seq, location_t);
 extern void gimple_seq_discard (gimple_seq);
 extern void maybe_remove_unused_call_args (struct function *, gimple *);
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 9c88765d1fb..a166b706b8a 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -891,7 +891,7 @@ static void move_block_after_check (rtx_insn *);
 static void move_succs (vec<edge, va_gc> **, basic_block);
 static void sched_remove_insn (rtx_insn *);
 static void clear_priorities (rtx_insn *, rtx_vec_t *);
-static void calc_priorities (rtx_vec_t);
+static void calc_priorities (const rtx_vec_t &);
 static void add_jump_dependencies (rtx_insn *, rtx_insn *);
 
 #endif /* INSN_SCHEDULING */
@@ -7375,10 +7375,10 @@ haifa_sched_init (void)
     basic_block bb;
     FOR_EACH_BB_FN (bb, cfun)
       bbs.quick_push (bb);
-    sched_init_luids (bbs);
+    sched_init_luids (bbs.to_vec ());
     sched_deps_init (true);
     sched_extend_target ();
-    haifa_init_h_i_d (bbs);
+    haifa_init_h_i_d (bbs.to_vec ());
   }
 
   sched_init_only_bb = haifa_init_only_bb;
@@ -8923,7 +8923,7 @@ clear_priorities (rtx_insn *insn, rtx_vec_t *roots_ptr)
    changed.  ROOTS is a vector of instructions whose priority computation will
    trigger initialization of all cleared priorities.  */
 static void
-calc_priorities (rtx_vec_t roots)
+calc_priorities (const rtx_vec_t &roots)
 {
   int i;
   rtx_insn *insn;
@@ -8988,7 +8988,7 @@ sched_init_insn_luid (rtx_insn *insn)
    The hook common_sched_info->luid_for_non_insn () is used to determine
    if notes, labels, etc. need luids.  */
 void
-sched_init_luids (bb_vec_t bbs)
+sched_init_luids (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
@@ -9062,7 +9062,7 @@ init_h_i_d (rtx_insn *insn)
 
 /* Initialize haifa_insn_data for BBS.  */
 void
-haifa_init_h_i_d (bb_vec_t bbs)
+haifa_init_h_i_d (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 57c18af2bab..ce28ada19fe 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -2946,9 +2946,9 @@ propagate_constants_across_call (struct cgraph_edge *cs)
 
 static tree
 ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
-				vec<tree> known_csts,
-				vec<ipa_polymorphic_call_context> known_contexts,
-				vec<ipa_agg_value_set> known_aggs,
+				const vec<tree> &known_csts,
+				const vec<ipa_polymorphic_call_context> &known_contexts,
+				const vec<ipa_agg_value_set> &known_aggs,
 				struct ipa_agg_replacement_value *agg_reps,
 				bool *speculative)
 {
@@ -2985,7 +2985,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 	    }
 	  if (!t)
 	    {
-	      struct ipa_agg_value_set *agg;
+	      const ipa_agg_value_set *agg;
 	      if (known_aggs.length () > (unsigned int) param_index)
 		agg = &known_aggs[param_index];
 	      else
@@ -3045,7 +3045,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   if (!t && known_aggs.length () > (unsigned int) param_index
       && !ie->indirect_info->by_ref)
     {
-      struct ipa_agg_value_set *agg = &known_aggs[param_index];
+      const ipa_agg_value_set *agg = &known_aggs[param_index];
       t = ipa_find_agg_cst_for_param (agg,
 				      (unsigned) param_index
 					 < known_csts.length ()
@@ -4267,7 +4267,7 @@ get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
    this kind of adjustment is possible.  */
 
 static bool
-adjust_callers_for_value_intersection (vec<cgraph_edge *> callers,
+adjust_callers_for_value_intersection (vec<cgraph_edge *> &callers,
 				       cgraph_node *node)
 {
   for (unsigned i = 0; i < callers.length (); i++)
@@ -4725,8 +4725,8 @@ self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
 
 static void
 find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
-					    vec<tree> known_csts,
-					    vec<cgraph_edge *> callers)
+					    vec<tree> &known_csts,
+					    const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -4818,7 +4818,7 @@ static void
 find_more_contexts_for_caller_subset (cgraph_node *node,
 				      vec<ipa_polymorphic_call_context>
 				      *known_contexts,
-				      vec<cgraph_edge *> callers)
+				      const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -5179,7 +5179,7 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
 
 static struct ipa_agg_replacement_value *
 find_aggregate_values_for_callers_subset (struct cgraph_node *node,
-					  vec<cgraph_edge *> callers)
+					  const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *dest_info = ipa_node_params_sum->get (node);
   struct ipa_agg_replacement_value *res;
@@ -5413,7 +5413,7 @@ known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts)
 /* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL.  */
 
 static vec<ipa_polymorphic_call_context>
-copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts)
+copy_useful_known_contexts (const vec<ipa_polymorphic_call_context> &known_contexts)
 {
   if (known_contexts_useful_p (known_contexts))
     return known_contexts.copy ();
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 95d28757f95..cf80ce3c040 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -3967,8 +3967,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 		      class ipa_fn_summary *info,
 		      class ipa_node_params *params_summary,
 		      class ipa_fn_summary *callee_info,
-		      vec<int> operand_map,
-		      vec<HOST_WIDE_INT> offset_map,
+		      const vec<int> &operand_map,
+		      const vec<HOST_WIDE_INT> &offset_map,
 		      clause_t possible_truths,
 		      predicate *toplev_predicate)
 {
@@ -4028,8 +4028,8 @@ remap_freqcounting_predicate (class ipa_fn_summary *info,
 			      class ipa_node_params *params_summary,
 			      class ipa_fn_summary *callee_info,
 			      vec<ipa_freqcounting_predicate, va_gc> *v,
-			      vec<int> operand_map,
-			      vec<HOST_WIDE_INT> offset_map,
+			      const vec<int> &operand_map,
+			      const vec<HOST_WIDE_INT> &offset_map,
 			      clause_t possible_truths,
 			      predicate *toplev_predicate)
 
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 9d896beb2ac..413446bcc46 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1774,7 +1774,7 @@ compute_max_insns (cgraph_node *node, int insns)
 /* Compute badness of all edges in NEW_EDGES and add them to the HEAP.  */
 
 static void
-add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
+add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> &new_edges)
 {
   while (new_edges.length () > 0)
     {
diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c
index 6dd749b8ffa..e4b11ec3ae3 100644
--- a/gcc/ipa-predicate.c
+++ b/gcc/ipa-predicate.c
@@ -507,8 +507,8 @@ predicate
 predicate::remap_after_inlining (class ipa_fn_summary *info,
 				 class ipa_node_params *params_summary,
 				 class ipa_fn_summary *callee_info,
-				 vec<int> operand_map,
-				 vec<HOST_WIDE_INT> offset_map,
+				 const vec<int> &operand_map,
+				 const vec<HOST_WIDE_INT> &offset_map,
 				 clause_t possible_truths,
 				 const predicate &toplev_predicate)
 {
diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h
index 3ed71046c0c..ac52b54aa36 100644
--- a/gcc/ipa-predicate.h
+++ b/gcc/ipa-predicate.h
@@ -243,7 +243,7 @@ public:
   predicate remap_after_inlining (class ipa_fn_summary *,
 		  		  class ipa_node_params *params_summary,
 			          class ipa_fn_summary *,
-				  vec<int>, vec<HOST_WIDE_INT>,
+				  const vec<int> &, const vec<HOST_WIDE_INT> &,
 				  clause_t, const predicate &);
 
   void stream_in (class lto_input_block *);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index f74d2e17b69..43f46a578c6 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -3562,7 +3562,7 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
    initializer of a constant.  */
 
 tree
-ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 			    HOST_WIDE_INT offset, bool by_ref,
 			    bool *from_global_constant)
 {
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 3d28a6e8640..d1cd42263f5 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
@@ -1092,7 +1092,7 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value,
 void ipa_analyze_node (struct cgraph_node *);
 
 /* Aggregate jump function related functions.  */
-tree ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 				 HOST_WIDE_INT offset, bool by_ref,
 				 bool *from_global_constant = NULL);
 bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 4031ce18287..42120656366 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -1672,7 +1672,7 @@ finish_cost_vectors (void)
 
 static vec<ira_loop_tree_node_t>
 ira_loop_tree_body_rev_postorder (ira_loop_tree_node_t loop_node ATTRIBUTE_UNUSED,
-				  vec<ira_loop_tree_node_t> loop_preorder)
+				  const vec<ira_loop_tree_node_t> &loop_preorder)
 {
   vec<ira_loop_tree_node_t> topsort_nodes = vNULL;
   unsigned int n_loop_preorder;
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925402877ec..e9eb1049e37 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -937,7 +937,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
 	}
 
       if (oname)
-	add_overload_instance (oname, iterators, x);
+	add_overload_instance (oname, iterators.to_vec (), x);
 
       /* Add the new rtx to the end of the queue.  */
       queue->safe_push (x);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 5ed0d6dd6fa..2faf4ac4f97 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2416,9 +2416,9 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
 			       struct full_rtx_costs *);
 extern bool native_encode_rtx (machine_mode, rtx, vec<target_unit> &,
 			       unsigned int, unsigned int);
-extern rtx native_decode_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_rtx (machine_mode, const vec<target_unit> &,
 			      unsigned int);
-extern rtx native_decode_vector_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_vector_rtx (machine_mode, const vec<target_unit> &,
 				     unsigned int, unsigned int, unsigned int);
 extern poly_uint64 subreg_lsb (const_rtx);
 extern poly_uint64 subreg_size_lsb (poly_uint64, poly_uint64, poly_uint64);
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 4727ab28920..868f1eb6c89 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -43,12 +43,12 @@ extern void sched_init_bbs (void);
 
 extern void sched_extend_luids (void);
 extern void sched_init_insn_luid (rtx_insn *);
-extern void sched_init_luids (bb_vec_t);
+extern void sched_init_luids (const bb_vec_t &);
 extern void sched_finish_luids (void);
 
 extern void sched_extend_target (void);
 
-extern void haifa_init_h_i_d (bb_vec_t);
+extern void haifa_init_h_i_d (const bb_vec_t &);
 extern void haifa_finish_h_i_d (void);
 
 /* Hooks that are common to all the schedulers.  */
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index c82101c73a4..113991ddff4 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -6742,7 +6742,7 @@ native_encode_rtx (machine_mode mode, rtx x, vec<target_unit> &bytes,
    Return the vector on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_vector_rtx (machine_mode mode, const vec<target_unit> &bytes,
 			  unsigned int first_byte, unsigned int npatterns,
 			  unsigned int nelts_per_pattern)
 {
@@ -6787,7 +6787,7 @@ native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
    Return the rtx on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_rtx (machine_mode mode, const vec<target_unit> &bytes,
 		   unsigned int first_byte)
 {
   if (VECTOR_MODE_P (mode))
diff --git a/gcc/tree-call-cdce.c b/gcc/tree-call-cdce.c
index 666839755d0..d9b9b4c6e84 100644
--- a/gcc/tree-call-cdce.c
+++ b/gcc/tree-call-cdce.c
@@ -761,7 +761,7 @@ get_no_error_domain (enum built_in_function fnc)
    condition are separated by NULL tree in the vector.  */
 
 static void
-gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
+gen_shrink_wrap_conditions (gcall *bi_call, const vec<gimple *> &conds,
                             unsigned int *nconds)
 {
   gcall *call;
@@ -797,7 +797,8 @@ gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
    when it is non-null, it is called while all of the CONDS are true.  */
 
 static void
-shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
+shrink_wrap_one_built_in_call_with_conds (gcall *bi_call,
+					  const vec <gimple *> &conds,
 					  unsigned int nconds,
 					  gcall *bi_newcall = NULL)
 {
@@ -1132,7 +1133,7 @@ use_internal_fn (gcall *call)
    wrapping transformation.  */
 
 static void
-shrink_wrap_conditional_dead_built_in_calls (vec<gcall *> calls)
+shrink_wrap_conditional_dead_built_in_calls (const vec<gcall *> &calls)
 {
   unsigned i = 0;
 
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b6abd8b8de7..210ac2851a5 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -2643,7 +2643,7 @@ create_intersect_range_checks (class loop *loop, tree *cond_expr,
 
 void
 create_runtime_alias_checks (class loop *loop,
-			     vec<dr_with_seg_len_pair_t> *alias_pairs,
+			     const vec<dr_with_seg_len_pair_t> *alias_pairs,
 			     tree * cond_expr)
 {
   tree part_cond_expr;
@@ -5635,9 +5635,9 @@ compute_affine_dependence (struct data_dependence_relation *ddr,
    is small enough to be handled.  */
 
 bool
-compute_all_dependences (vec<data_reference_p> datarefs,
+compute_all_dependences (const vec<data_reference_p> &datarefs,
 			 vec<ddr_p> *dependence_relations,
-			 vec<loop_p> loop_nest,
+			 const vec<loop_p> &loop_nest,
 			 bool compute_self_and_rr)
 {
   struct data_dependence_relation *ddr;
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8001cc54f51..a0ff2a80263 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -551,9 +551,9 @@ extern struct data_dependence_relation *initialize_data_dependence_relation
 extern void compute_affine_dependence (struct data_dependence_relation *,
 				       loop_p);
 extern void compute_self_dependence (struct data_dependence_relation *);
-extern bool compute_all_dependences (vec<data_reference_p> ,
+extern bool compute_all_dependences (const vec<data_reference_p> &,
 				     vec<ddr_p> *,
-				     vec<loop_p>, bool);
+				     const vec<loop_p> &, bool);
 extern tree find_data_references_in_bb (class loop *, basic_block,
                                         vec<data_reference_p> *);
 extern unsigned int dr_alignment (innermost_loop_behavior *);
@@ -578,7 +578,8 @@ extern int data_ref_compare_tree (tree, tree);
 extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
 					   poly_uint64);
 extern void create_runtime_alias_checks (class loop *,
-					 vec<dr_with_seg_len_pair_t> *, tree*);
+					 const vec<dr_with_seg_len_pair_t> *,
+					 tree*);
 extern tree dr_direction_indicator (struct data_reference *);
 extern tree dr_zero_step_indicator (struct data_reference *);
 extern bool dr_known_forward_stride_p (struct data_reference *);
@@ -666,7 +667,7 @@ ddr_dependence_level (ddr_p ddr)
 /* Return the index of the variable VAR in the LOOP_NEST array.  */
 
 static inline int
-index_in_loop_nest (int var, vec<loop_p> loop_nest)
+index_in_loop_nest (int var, const vec<loop_p> &loop_nest)
 {
   class loop *loopi;
   int var_index;
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 345488e2a19..49e89cffa1a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -2208,7 +2208,7 @@ insert_gimplified_predicates (loop_p loop)
    mask if it was created for given SIZE and -1 otherwise.  */
 
 static int
-mask_exists (int size, vec<int> vec)
+mask_exists (int size, const vec<int> &vec)
 {
   unsigned int ix;
   int v;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 65aa1df4aba..7b715d684f5 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -527,7 +527,7 @@ class loop_distribution
 
   /* Build the vertices of the reduced dependence graph RDG.  Return false
      if that failed.  */
-  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts, loop_p loop);
+  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> &stmts, loop_p loop);
 
   /* Initialize STMTS with all the statements of LOOP.  We use topological
      order to discover all statements.  The order is important because
@@ -646,7 +646,7 @@ class loop_distribution
      statements from STMTS into separate loops.  Returns the number of
      distributed loops.  Set NB_CALLS to number of generated builtin calls.
      Set *DESTROY_P to whether LOOP needs to be destroyed.  */
-  int distribute_loop (class loop *loop, vec<gimple *> stmts,
+  int distribute_loop (class loop *loop, const vec<gimple *> &stmts,
 		       control_dependences *cd, int *nb_calls, bool *destroy_p,
 		       bool only_patterns_p);
 
@@ -699,7 +699,7 @@ bb_top_order_cmp_r (const void *x, const void *y, void *loop)
 }
 
 bool
-loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts,
+loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> &stmts,
 					loop_p loop)
 {
   int i;
@@ -1953,7 +1953,7 @@ loop_distribution::rdg_build_partitions (struct graph *rdg,
 /* Dump to FILE the PARTITIONS.  */
 
 static void
-dump_rdg_partitions (FILE *file, vec<partition *> partitions)
+dump_rdg_partitions (FILE *file, const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -1963,10 +1963,10 @@ dump_rdg_partitions (FILE *file, vec<partition *> partitions)
 }
 
 /* Debug PARTITIONS.  */
-extern void debug_rdg_partitions (vec<partition *> );
+extern void debug_rdg_partitions (const vec<partition *> &);
 
 DEBUG_FUNCTION void
-debug_rdg_partitions (vec<partition *> partitions)
+debug_rdg_partitions (const vec<partition *> &partitions)
 {
   dump_rdg_partitions (stderr, partitions);
 }
@@ -2017,7 +2017,7 @@ number_of_rw_in_partition (struct graph *rdg, partition *partition)
 
 static bool
 partition_contains_all_rw (struct graph *rdg,
-			   vec<partition *> partitions)
+			   const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -2921,7 +2921,8 @@ loop_distribution::finalize_partitions (class loop *loop,
    Set *DESTROY_P to whether LOOP needs to be destroyed.  */
 
 int
-loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts,
+loop_distribution::distribute_loop (class loop *loop,
+		 const vec<gimple *> &stmts,
 		 control_dependences *cd, int *nb_calls, bool *destroy_p,
 		 bool only_patterns_p)
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index fe1baef32a7..bb547572653 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -3713,7 +3713,7 @@ ref_conflicts_with_region (gimple_stmt_iterator gsi, ao_ref *ref,
    reduction results in REDUCTION_STORES.  */
 
 static bool
-oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_ok_1 (bitmap in_loop_bbs, const vec<basic_block> &region_bbs,
 		      reduction_info_table_type *reduction_list,
 		      bitmap reduction_stores)
 {
@@ -3828,7 +3828,8 @@ oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
    if any changes were made.  */
 
 static bool
-oacc_entry_exit_single_gang (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_single_gang (bitmap in_loop_bbs,
+			     const vec<basic_block> &region_bbs,
 			     bitmap reduction_stores)
 {
   tree gang_pos = NULL_TREE;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 7de47edbcb3..c778f7e87fd 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -2511,7 +2511,7 @@ sm_seq_valid_bb (class loop *loop, basic_block bb, tree vdef,
 
 static void
 hoist_memory_references (class loop *loop, bitmap mem_refs,
-			 vec<edge> exits)
+			 const vec<edge> &exits)
 {
   im_mem_ref *ref;
   unsigned  i;
@@ -2906,7 +2906,7 @@ find_refs_for_sm (class loop *loop, bitmap sm_executed, bitmap refs_to_sm)
 
 static bool
 loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
-		      vec<edge> exits)
+		      const vec<edge> &exits)
 {
   unsigned i;
   edge ex;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index b5add827018..3f9954c88a3 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3929,7 +3929,7 @@ wide_int_cmp (const void *p1, const void *p2)
    Lookup by binary search.  */
 
 static int
-bound_index (vec<widest_int> bounds, const widest_int &bound)
+bound_index (const vec<widest_int> &bounds, const widest_int &bound)
 {
   unsigned int end = bounds.length ();
   unsigned int begin = 0;
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index d86fe26bd07..a715cddc13d 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3100,7 +3100,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    vec<pre_expr> avail)
+			    vec<pre_expr> &avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 2dd4435b981..8498cfc7aa8 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -4486,7 +4486,7 @@ get_ops (tree var, enum tree_code code, vec<operand_entry *> *ops,
    stmts.  */
 
 static tree
-update_ops (tree var, enum tree_code code, vec<operand_entry *> ops,
+update_ops (tree var, enum tree_code code, const vec<operand_entry *> &ops,
 	    unsigned int *pidx, class loop *loop)
 {
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5033,7 +5033,7 @@ remove_visited_stmt_chain (tree var)
    cases, but it is unlikely to be worth it.  */
 
 static void
-swap_ops_for_binary_stmt (vec<operand_entry *> ops,
+swap_ops_for_binary_stmt (const vec<operand_entry *> &ops,
 			  unsigned int opindex, gimple *stmt)
 {
   operand_entry *oe1, *oe2, *oe3;
@@ -5104,7 +5104,8 @@ insert_stmt_before_use (gimple *stmt, gimple *stmt_to_insert)
 
 static tree
 rewrite_expr_tree (gimple *stmt, enum tree_code rhs_code, unsigned int opindex,
-		   vec<operand_entry *> ops, bool changed, bool next_changed)
+		   const vec<operand_entry *> &ops, bool changed,
+		   bool next_changed)
 {
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -5326,7 +5327,7 @@ get_reassociation_width (int ops_num, enum tree_code opc,
 
 static void
 rewrite_expr_tree_parallel (gassign *stmt, int width,
-			    vec<operand_entry *> ops)
+			    const vec<operand_entry *> &ops)
 {
   enum tree_code opcode = gimple_assign_rhs_code (stmt);
   int op_num = ops.length ();
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 64e3a707f5c..3451ff1f157 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1040,9 +1040,8 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
 bool
 ao_ref_init_from_vn_reference (ao_ref *ref,
 			       alias_set_type set, alias_set_type base_set,
-			       tree type, vec<vn_reference_op_s> ops)
+			       tree type, const vec<vn_reference_op_s> &ops)
 {
-  vn_reference_op_t op;
   unsigned i;
   tree base = NULL_TREE;
   tree *op0_p = &base;
@@ -1061,7 +1060,10 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
     size = wi::to_poly_offset (size_tree);
 
   /* Lower the final access size from the outermost expression.  */
-  op = &ops[0];
+  const_vn_reference_op_t cst_op = &ops[0];
+  /* Cast away constness for the sake of the const-unsafe
+     FOR_EACH_VEC_ELT().  */
+  vn_reference_op_t op = const_cast<vn_reference_op_t>(cst_op);
   size_tree = NULL_TREE;
   if (op->opcode == COMPONENT_REF)
     size_tree = DECL_SIZE (op->op0);
@@ -1092,7 +1094,7 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
 	      && op->op0
 	      && DECL_P (TREE_OPERAND (op->op0, 0)))
 	    {
-	      vn_reference_op_t pop = &ops[i-1];
+	      const_vn_reference_op_t pop = &ops[i-1];
 	      base = TREE_OPERAND (op->op0, 0);
 	      if (known_eq (pop->off, -1))
 		{
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 6df526c269b..96100596d2e 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -254,7 +254,7 @@ tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
 vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
 				       tree, tree *, tree, unsigned int);
 bool ao_ref_init_from_vn_reference (ao_ref *, alias_set_type, alias_set_type,
-				    tree, vec<vn_reference_op_s> );
+				    tree, const vec<vn_reference_op_s> &);
 vec<vn_reference_op_s> vn_reference_operands_for_lookup (tree);
 tree vn_reference_lookup_pieces (tree, alias_set_type, alias_set_type, tree,
 				 vec<vn_reference_op_s> ,
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 7163438e23d..4820f4591e4 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3713,8 +3713,8 @@ get_constraint_for_rhs (tree t, vec<ce_s> *results)
    entries in *LHSC.  */
 
 static void
-process_all_all_constraints (vec<ce_s> lhsc,
-			     vec<ce_s> rhsc)
+process_all_all_constraints (const vec<ce_s> &lhsc,
+			     const vec<ce_s> &rhsc)
 {
   struct constraint_expr *lhsp, *rhsp;
   unsigned i, j;
@@ -3814,7 +3814,7 @@ do_structure_copy (tree lhsop, tree rhsop)
 /* Create constraints ID = { rhsc }.  */
 
 static void
-make_constraints_to (unsigned id, vec<ce_s> rhsc)
+make_constraints_to (unsigned id, const vec<ce_s> &rhsc)
 {
   struct constraint_expr *c;
   struct constraint_expr includes;
@@ -4924,7 +4924,7 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
 	handle_rhs_call (t, &rhsc);
       if (gimple_call_lhs (t))
 	handle_lhs_call (t, gimple_call_lhs (t),
-			 gimple_call_return_flags (t), rhsc, fndecl);
+			 gimple_call_return_flags (t), rhsc.to_vec (), fndecl);
     }
   else
     {
@@ -5682,7 +5682,7 @@ fieldoff_compare (const void *pa, const void *pb)
 
 /* Sort a fieldstack according to the field offset and sizes.  */
 static void
-sort_fieldstack (vec<fieldoff_s> fieldstack)
+sort_fieldstack (vec<fieldoff_s> &fieldstack)
 {
   fieldstack.qsort (fieldoff_compare);
 }
@@ -6092,7 +6092,7 @@ create_function_info_for (tree decl, const char *name, bool add_id,
    FIELDSTACK is assumed to be sorted by offset.  */
 
 static bool
-check_for_overlaps (vec<fieldoff_s> fieldstack)
+check_for_overlaps (const vec<fieldoff_s> &fieldstack)
 {
   fieldoff_s *fo = NULL;
   unsigned int i;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 579149dfd61..1e929fa002c 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -208,7 +208,7 @@ vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 static void
 vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
 {
-  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
+  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < checks.length(); ++i)
     if (checks[i] == value)
       return;
@@ -2346,7 +2346,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   if (do_versioning)
     {
       vec<stmt_vec_info> may_misalign_stmts
-        = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
+	= LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo).to_vec ();
       stmt_vec_info stmt_info;
 
       /* It can now be assumed that the data references in the statements
@@ -3360,7 +3360,8 @@ static void
 vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
 			poly_uint64 min_value)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  vec<vec_lower_bound> lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     if (operand_equal_p (lower_bounds[i].expr, expr, 0))
       {
@@ -3462,7 +3463,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
   hash_set <tree_pair_hash> compared_objects;
 
-  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
+  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).to_vec ();
   vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
     = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
   vec<vec_object_pair> &check_unequal_addrs
@@ -5335,7 +5336,7 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
    I4:  6 14 22 30  7 15 23 31.  */
 
 void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> dr_chain,
+vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
 			  unsigned int length,
 			  stmt_vec_info stmt_info,
 			  gimple_stmt_iterator *gsi,
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index 012f48bd487..9ff48fec729 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -3168,7 +3168,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
                                    tree *cond_expr,
 				   gimple_seq *cond_expr_stmt_list)
 {
-  vec<stmt_vec_info> may_misalign_stmts
+  const vec<stmt_vec_info> &may_misalign_stmts
     = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
   stmt_vec_info stmt_info;
   int mask = LOOP_VINFO_PTR_MASK (loop_vinfo);
@@ -3259,7 +3259,8 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
 static void
 vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_object_pair> pairs = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
+  const vec<vec_object_pair> &pairs
+    = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
   unsigned int i;
   vec_object_pair *pair;
   FOR_EACH_VEC_ELT (pairs, i, pair)
@@ -3278,7 +3279,8 @@ vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 static void
 vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  const vec<vec_lower_bound> &lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     {
       tree expr = lower_bounds[i].expr;
@@ -3320,7 +3322,7 @@ vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 void
 vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
 {
-  vec<dr_with_seg_len_pair_t> comp_alias_ddrs =
+  const vec<dr_with_seg_len_pair_t> &comp_alias_ddrs =
     LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
 
   if (comp_alias_ddrs.is_empty ())
diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c
index d536494a1bd..571b29322c5 100644
--- a/gcc/tree-vect-slp-patterns.c
+++ b/gcc/tree-vect-slp-patterns.c
@@ -746,7 +746,7 @@ vect_match_call_complex_mla (slp_tree node, unsigned child,
    of the negate node.  */
 
 static inline bool
-vect_normalize_conj_loc (vec<slp_tree> args, bool *neg_first_p = NULL)
+vect_normalize_conj_loc (vec<slp_tree> &args, bool *neg_first_p = NULL)
 {
   gcc_assert (args.length () == 2);
   bool neg_found = false;
@@ -790,7 +790,8 @@ is_eq_or_top (complex_perm_kinds_t perm, complex_perm_kinds_t kind)
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> left_op, vec<slp_tree> right_op,
+			      const vec<slp_tree> &left_op,
+			      const vec<slp_tree> &right_op,
 			     bool neg_first, bool *conj_first_operand,
 			     bool fms)
 {
@@ -862,7 +863,8 @@ vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> op, complex_perm_kinds_t permKind)
+			      const vec<slp_tree> &op,
+			      complex_perm_kinds_t permKind)
 {
   /* The left node is the more common case, test it first.  */
   if (!is_eq_or_top (linear_loads_p (perm_cache, op[0]), permKind))
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 227d6aa3ee8..9aee024cbf7 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -3316,7 +3316,8 @@ vect_analyze_slp_instance (vec_info *vinfo,
   else if (kind == slp_inst_kind_reduc_group)
     {
       /* Collect reduction statements.  */
-      vec<stmt_vec_info> reductions = as_a <loop_vec_info> (vinfo)->reductions;
+      const vec<stmt_vec_info> &reductions
+	= as_a <loop_vec_info> (vinfo)->reductions;
       scalar_stmts.create (reductions.length ());
       for (i = 0; reductions.iterate (i, &next_info); i++)
 	if (STMT_VINFO_RELEVANT_P (next_info)
@@ -4047,7 +4048,8 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
 {
   unsigned int i;
   poly_uint64 unrolling_factor = 1;
-  vec<slp_instance> slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
+  const vec<slp_instance> &slp_instances
+    = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
   slp_instance instance;
   int decided_to_slp = 0;
 
@@ -5814,7 +5816,7 @@ vect_slp_region (vec<basic_block> bbs, vec<data_reference_p> datarefs,
    true if anything in the basic-block was vectorized.  */
 
 static bool
-vect_slp_bbs (vec<basic_block> bbs)
+vect_slp_bbs (const vec<basic_block> &bbs)
 {
   vec<data_reference_p> datarefs = vNULL;
   auto_vec<int> dataref_groups;
@@ -5959,7 +5961,7 @@ vect_slp_function (function *fun)
 
 void
 duplicate_and_interleave (vec_info *vinfo, gimple_seq *seq, tree vector_type,
-			  vec<tree> elts, unsigned int nresults,
+			  vec<tree> &elts, unsigned int nresults,
 			  vec<tree> &results)
 {
   unsigned int nelts = elts.length ();
@@ -6315,7 +6317,7 @@ vect_get_slp_defs (vec_info *,
 
 bool
 vect_transform_slp_perm_load (vec_info *vinfo,
-			      slp_tree node, vec<tree> dr_chain,
+			      slp_tree node, const vec<tree> &dr_chain,
 			      gimple_stmt_iterator *gsi, poly_uint64 vf,
 			      bool analyze_only, unsigned *n_perms,
 			      unsigned int *n_loads, bool dce_chain)
@@ -7329,7 +7331,7 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance,
 /* Generate vector code for SLP_INSTANCES in the loop/basic block.  */
 
 void
-vect_schedule_slp (vec_info *vinfo, vec<slp_instance> slp_instances)
+vect_schedule_slp (vec_info *vinfo, const vec<slp_instance> &slp_instances)
 {
   slp_instance instance;
   unsigned int i;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 4ee11b2041a..7d99199b968 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4437,7 +4437,7 @@ static void
 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
 				       int multi_step_cvt,
 				       stmt_vec_info stmt_info,
-				       vec<tree> vec_dsts,
+				       vec<tree> &vec_dsts,
 				       gimple_stmt_iterator *gsi,
 				       slp_tree slp_node, enum tree_code code)
 {
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index fa28336d429..688bdaffcb5 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1927,8 +1927,8 @@ extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT);
 extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
 extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
 extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
-extern void vect_permute_store_chain (vec_info *,
-				      vec<tree> ,unsigned int, stmt_vec_info,
+extern void vect_permute_store_chain (vec_info *, vec<tree> &,
+				      unsigned int, stmt_vec_info,
 				      gimple_stmt_iterator *, vec<tree> *);
 extern tree vect_setup_realignment (vec_info *,
 				    stmt_vec_info, gimple_stmt_iterator *,
@@ -2009,12 +2009,12 @@ extern tree cse_and_gimplify_to_preheader (loop_vec_info, tree);
 extern void vect_slp_init (void);
 extern void vect_slp_fini (void);
 extern void vect_free_slp_instance (slp_instance);
-extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, vec<tree>,
+extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, const vec<tree> &,
 					  gimple_stmt_iterator *, poly_uint64,
 					  bool, unsigned *,
 					  unsigned * = nullptr, bool = false);
 extern bool vect_slp_analyze_operations (vec_info *);
-extern void vect_schedule_slp (vec_info *, vec<slp_instance>);
+extern void vect_schedule_slp (vec_info *, const vec<slp_instance> &);
 extern opt_result vect_analyze_slp (vec_info *, unsigned);
 extern bool vect_make_slp_decision (loop_vec_info);
 extern void vect_detect_hybrid_slp (loop_vec_info);
@@ -2032,7 +2032,7 @@ extern bool can_duplicate_and_interleave_p (vec_info *, unsigned int, tree,
 					    unsigned int * = NULL,
 					    tree * = NULL, tree * = NULL);
 extern void duplicate_and_interleave (vec_info *, gimple_seq *, tree,
-				      vec<tree>, unsigned int, vec<tree> &);
+				      vec<tree> &, unsigned int, vec<tree> &);
 extern int vect_get_place_in_interleaving_chain (stmt_vec_info, stmt_vec_info);
 extern bool vect_update_shared_vectype (stmt_vec_info, tree);
 extern slp_tree vect_create_new_slp_node (unsigned, tree_code);
diff --git a/gcc/tree.c b/gcc/tree.c
index 1aa6e557a04..bead1ac134c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2047,7 +2047,7 @@ make_vector (unsigned log2_npatterns,
    are extracted from V, a vector of CONSTRUCTOR_ELT.  */
 
 tree
-build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
+build_vector_from_ctor (tree type, const vec<constructor_elt, va_gc> *v)
 {
   if (vec_safe_length (v) == 0)
     return build_zero_cst (type);
@@ -14428,7 +14428,7 @@ test_labels ()
    are given by VALS.  */
 
 static tree
-build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
+build_vector (tree type, const vec<tree> &vals MEM_STAT_DECL)
 {
   gcc_assert (known_eq (vals.length (), TYPE_VECTOR_SUBPARTS (type)));
   tree_vector_builder builder (type, vals.length (), 1);
@@ -14439,7 +14439,7 @@ build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
 /* Check that VECTOR_CST ACTUAL contains the elements in EXPECTED.  */
 
 static void
-check_vector_cst (vec<tree> expected, tree actual)
+check_vector_cst (const vec<tree> &expected, tree actual)
 {
   ASSERT_KNOWN_EQ (expected.length (),
 		   TYPE_VECTOR_SUBPARTS (TREE_TYPE (actual)));
@@ -14452,7 +14452,7 @@ check_vector_cst (vec<tree> expected, tree actual)
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_duplicate (vec<tree> expected, tree actual,
+check_vector_cst_duplicate (const vec<tree> &expected, tree actual,
 			    unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14468,7 +14468,7 @@ check_vector_cst_duplicate (vec<tree> expected, tree actual,
    EXPECTED.  */
 
 static void
-check_vector_cst_fill (vec<tree> expected, tree actual,
+check_vector_cst_fill (const vec<tree> &expected, tree actual,
 		       unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14483,7 +14483,7 @@ check_vector_cst_fill (vec<tree> expected, tree actual,
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_stepped (vec<tree> expected, tree actual,
+check_vector_cst_stepped (const vec<tree> &expected, tree actual,
 			  unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
diff --git a/gcc/tree.h b/gcc/tree.h
index 060ddee09dd..7043ae2cddc 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4474,7 +4474,7 @@ extern tree build_int_cst (tree, poly_int64);
 extern tree build_int_cstu (tree type, poly_uint64);
 extern tree build_int_cst_type (tree, poly_int64);
 extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO);
-extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
+extern tree build_vector_from_ctor (tree, const vec<constructor_elt, va_gc> *);
 extern tree build_vector_from_val (tree, tree);
 extern tree build_uniform_cst (tree, tree);
 extern tree build_vec_series (tree, tree, tree);
diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..6d767cc12c1 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -38,16 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #endif
 
-/* vNULL is an empty type with a template cast operation that returns
-   a zero-initialized vec<T, A, L> instance.  Use this when you want
-   to assign nil values to new vec instances or pass a nil vector as
-   a function call argument.
-
-   We use this technique because vec<T, A, L> must be PODs (they are
-   stored in unions and passed in vararg functions), this means that
-   they cannot have ctors/dtors.  */
-vnull vNULL;
-
 /* Vector memory usage.  */
 class vec_usage: public mem_usage
 {
@@ -282,6 +272,42 @@ safe_push_range (vec <int>&v, int start, int limit)
     v.safe_push (i);
 }
 
+/* Verify forms of initialization.  */
+
+static void
+test_init ()
+{
+  {
+    vec<int> v1{ };
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 = vec<int>();
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 = v1;
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 (vNULL);
+    ASSERT_EQ (0, v1.length ());
+    v1.safe_push (1);
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (1, v1.length ());
+    v2.safe_push (1);
+
+    ASSERT_EQ (2, v1.length ());
+    ASSERT_EQ (2, v2.length ());
+    v1.release ();
+  }
+}
+
 /* Verify that vec::quick_push works correctly.  */
 
 static void
@@ -547,6 +573,7 @@ test_auto_delete_vec ()
 void
 vec_c_tests ()
 {
+  test_init ();
   test_quick_push ();
   test_safe_push ();
   test_truncate ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..fef3dda6a38 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -541,18 +541,16 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
     ::new (static_cast<void*>(dst)) T (*src);
 }
 
-/* Type to provide NULL values for vec<T, A, L>.  This is used to
-   provide nil initializers for vec instances.  Since vec must be
-   a POD, we cannot have proper ctor/dtor for it.  To initialize
-   a vec instance, you can assign it the value vNULL.  This isn't
-   needed for file-scope and function-local static vectors, which
-   are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
-extern vnull vNULL;
+/* Type to provide zero-initialized values for vec<T, A, L>.  This is
+   used to  provide nil initializers for vec instances.  Since vec must
+   be a trivially copyable type that can be copied by memcpy and zeroed
+   out by memset, it must have defaulted default and copy ctor and copy
+   assignment.  To initialize a vec either use value initialization
+   (e.g., vec() or vec v{ };) or assign it the value vNULL.  This isn't
+   needed for file-scope and function-local static vectors, which are
+   zero-initialized by default.  */
+struct vnull { };
+static constexpr vnull vNULL{ };
 
 
 /* Embeddable vector.  These vectors are suitable to be embedded
@@ -1431,10 +1429,34 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
    As long as we use C++03, we cannot have constructors nor
    destructors in classes that are stored in unions.  */
 
+template<typename T, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  /* Default ctors to ensure triviality.  Use value-initialization
+     (e.g., vec() or vec v{ };) or vNULL to create a zero-initialized
+     instance.  */
+  vec () = default;
+  vec (const vec &) = default;
+  /* Initialization from the generic vNULL.  */
+  vec (vnull): m_vec () { }
+  /* Same as default ctor: vec storage must be released manually.  */
+  ~vec () = default;
+
+  /* Defaulted same as copy ctor.  */
+  vec& operator= (const vec &) = default;
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1544,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1571,13 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1631,13 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // 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 ().
@@ -1781,7 +1817,7 @@ template<typename T>
 inline vec<T, va_heap, vl_ptr>
 vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
 {
-  vec<T, va_heap, vl_ptr> new_vec = vNULL;
+  vec<T, va_heap, vl_ptr> new_vec{ };
   if (length ())
     new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT);
   return new_vec;

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-25 20:51               ` Martin Sebor
@ 2021-06-25 22:11                 ` Jason Merrill
  2021-06-25 22:36                   ` Martin Sebor
  2021-06-28  8:05                 ` Richard Biener
  2021-06-29 12:30                 ` Trevor Saunders
  2 siblings, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-06-25 22:11 UTC (permalink / raw)
  To: Martin Sebor, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

On 6/25/21 4:51 PM, Martin Sebor wrote:
> On 6/1/21 3:38 PM, Jason Merrill wrote:
>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> 
>>>>>> wrote:
>>>>>>>
>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>
>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>> assignment operator.
>>>>>>>>>
>>>>>>>>> The attached patch adds the two special functions to auto_vec 
>>>>>>>>> along
>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in 
>>>>>>>>> containers
>>>>>>>>> that expect copyable and assignable element types and passes 
>>>>>>>>> bootstrap
>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>
>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>>>>> operators?
>>>>>>>
>>>>>>> I would strongly prefer the generic vector class to have the 
>>>>>>> properties
>>>>>>> expected of any other generic container: copyable and 
>>>>>>> assignable.  If
>>>>>>> we also want another vector type with this restriction I suggest 
>>>>>>> to add
>>>>>>> another "noncopyable" type and make that property explicit in its 
>>>>>>> name.
>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>
>>>>>> I'm not sure (and not strictly against the copy and assign). 
>>>>>> Looking around
>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>>> might be surprising (I added the move capability to match how vec<>
>>>>>> is used - as "reference" to a vector)
>>>>>
>>>>> The vec base classes are special: they have no ctors at all (because
>>>>> of their use in unions).  That's something we might have to live with
>>>>> but it's not a model to follow in ordinary containers.
>>>>
>>>> I don't think we have to live with it anymore, now that we're 
>>>> writing C++11.
>>>>
>>>>> The auto_vec class was introduced to fill the need for a conventional
>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>> This change fixes that oversight.
>>>>>
>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>> primary template (that's also missing it).  In addition, it adds
>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>> assignment as you prefer.
>>>>
>>>> Hmm, adding another class doesn't really help with the confusion 
>>>> richi mentions.  And many uses of auto_vec will pass them as vec, 
>>>> which will still do a shallow copy.  I think it's probably better to 
>>>> disable the copy special members for auto_vec until we fix vec<>.
>>>
>>> There are at least a couple of problems that get in the way of fixing
>>> all of vec to act like a well-behaved C++ container:
>>>
>>> 1) The embedded vec has a trailing "flexible" array member with its
>>> instances having different size.  They're initialized by memset and
>>> copied by memcpy.  The class can't have copy ctors or assignments
>>> but it should disable/delete them instead.
>>>
>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>> shallow copy semantics (not just as function arguments but also as
>>> members of other such POD classes).  This can be changed by providing
>>> copy and move ctors and assignment operators for it, and also for
>>> some of the classes in which it's a member and that are used with
>>> the same assumption.
>>>
>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>> and tree-vect-patterns.c).
>>>
>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>> be a big and tricky project.  Tricky because it involves using
>>> std::move in places where what's moved is subsequently still used.
>>> I can keep plugging away at it but it won't change the fact that
>>> the embedded and heap-based vecs have different requirements.
>>>
>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>> to be put on hold until the rats nest above is untangled.  It won't
>>> make anything worse than it is.  (I have a project that depends on
>>> a sane auto_vec working).
>>>
>>> A couple of alternatives to solving this are to use std::vector or
>>> write an equivalent vector class just for GCC.
>>
>> It occurs to me that another way to work around the issue of passing 
>> an auto_vec by value as a vec, and thus doing a shallow copy, would be 
>> to add a vec ctor taking an auto_vec, and delete that.  This would 
>> mean if you want to pass an auto_vec to a vec interface, it needs to 
>> be by reference.  We might as well do the same for operator=, though 
>> that isn't as important.
> 
> Thanks, that sounds like a good idea.  Attached is an implementation
> of this change.  Since the auto_vec copy ctor and assignment have
> been deleted by someone else in the interim, this patch doesn't
> reverse that.  I will propose it separately after these changes
> are finalized.
> 
> My approach was to 1) disable the auto_vec to vec conversion,
> 2) introduce an auto_vec::to_vec() to make the conversion possible
> explicitly, and 3) resolve compilation errors by either changing
> APIs to take a vec by reference or callers to convert auto_vec to
> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> improving the const-correctness of the APIs.

What did you base the choice between reference or to_vec on?  For 
instance, it seems like c_parser_declaration_or_fndef could use a 
reference, but you changed the callers instead.

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-25 22:11                 ` Jason Merrill
@ 2021-06-25 22:36                   ` Martin Sebor
  2021-06-28  8:07                     ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-06-25 22:36 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

On 6/25/21 4:11 PM, Jason Merrill wrote:
> On 6/25/21 4:51 PM, Martin Sebor wrote:
>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> 
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>
>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>> assignment operator.
>>>>>>>>>>
>>>>>>>>>> The attached patch adds the two special functions to auto_vec 
>>>>>>>>>> along
>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in 
>>>>>>>>>> containers
>>>>>>>>>> that expect copyable and assignable element types and passes 
>>>>>>>>>> bootstrap
>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>
>>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>>> can be quite inefficient?  Thus the option is to delete those 
>>>>>>>>> operators?
>>>>>>>>
>>>>>>>> I would strongly prefer the generic vector class to have the 
>>>>>>>> properties
>>>>>>>> expected of any other generic container: copyable and 
>>>>>>>> assignable.  If
>>>>>>>> we also want another vector type with this restriction I suggest 
>>>>>>>> to add
>>>>>>>> another "noncopyable" type and make that property explicit in 
>>>>>>>> its name.
>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>
>>>>>>> I'm not sure (and not strictly against the copy and assign). 
>>>>>>> Looking around
>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>>>> might be surprising (I added the move capability to match how vec<>
>>>>>>> is used - as "reference" to a vector)
>>>>>>
>>>>>> The vec base classes are special: they have no ctors at all (because
>>>>>> of their use in unions).  That's something we might have to live with
>>>>>> but it's not a model to follow in ordinary containers.
>>>>>
>>>>> I don't think we have to live with it anymore, now that we're 
>>>>> writing C++11.
>>>>>
>>>>>> The auto_vec class was introduced to fill the need for a conventional
>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>> This change fixes that oversight.
>>>>>>
>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>> assignment as you prefer.
>>>>>
>>>>> Hmm, adding another class doesn't really help with the confusion 
>>>>> richi mentions.  And many uses of auto_vec will pass them as vec, 
>>>>> which will still do a shallow copy.  I think it's probably better 
>>>>> to disable the copy special members for auto_vec until we fix vec<>.
>>>>
>>>> There are at least a couple of problems that get in the way of fixing
>>>> all of vec to act like a well-behaved C++ container:
>>>>
>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>> instances having different size.  They're initialized by memset and
>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>> but it should disable/delete them instead.
>>>>
>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>> shallow copy semantics (not just as function arguments but also as
>>>> members of other such POD classes).  This can be changed by providing
>>>> copy and move ctors and assignment operators for it, and also for
>>>> some of the classes in which it's a member and that are used with
>>>> the same assumption.
>>>>
>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>> and tree-vect-patterns.c).
>>>>
>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>> be a big and tricky project.  Tricky because it involves using
>>>> std::move in places where what's moved is subsequently still used.
>>>> I can keep plugging away at it but it won't change the fact that
>>>> the embedded and heap-based vecs have different requirements.
>>>>
>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>> make anything worse than it is.  (I have a project that depends on
>>>> a sane auto_vec working).
>>>>
>>>> A couple of alternatives to solving this are to use std::vector or
>>>> write an equivalent vector class just for GCC.
>>>
>>> It occurs to me that another way to work around the issue of passing 
>>> an auto_vec by value as a vec, and thus doing a shallow copy, would 
>>> be to add a vec ctor taking an auto_vec, and delete that.  This would 
>>> mean if you want to pass an auto_vec to a vec interface, it needs to 
>>> be by reference.  We might as well do the same for operator=, though 
>>> that isn't as important.
>>
>> Thanks, that sounds like a good idea.  Attached is an implementation
>> of this change.  Since the auto_vec copy ctor and assignment have
>> been deleted by someone else in the interim, this patch doesn't
>> reverse that.  I will propose it separately after these changes
>> are finalized.
>>
>> My approach was to 1) disable the auto_vec to vec conversion,
>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>> explicitly, and 3) resolve compilation errors by either changing
>> APIs to take a vec by reference or callers to convert auto_vec to
>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>> improving the const-correctness of the APIs.
> 
> What did you base the choice between reference or to_vec on?  For 
> instance, it seems like c_parser_declaration_or_fndef could use a 
> reference, but you changed the callers instead.

I went with a reference whenever I could.  That doesn't work when
there are callers that pass in a vNULL, so there, and in assignments,
I used to_vec().

Martin


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-25 20:51               ` Martin Sebor
  2021-06-25 22:11                 ` Jason Merrill
@ 2021-06-28  8:05                 ` Richard Biener
  2021-06-29 12:30                 ` Trevor Saunders
  2 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2021-06-28  8:05 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Fri, Jun 25, 2021 at 10:52 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/1/21 3:38 PM, Jason Merrill wrote:
> > On 6/1/21 3:56 PM, Martin Sebor wrote:
> >> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> >>>>>>
> >>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>
> >>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
> >>>>>>>> the class manages its own memory but doesn't define (or delete)
> >>>>>>>> either special function.  Since I first ran into the problem,
> >>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>> assignment operator.
> >>>>>>>>
> >>>>>>>> The attached patch adds the two special functions to auto_vec along
> >>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>> containers
> >>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>> bootstrap
> >>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>
> >>>>>>> The question is whether we want such uses to appear since those
> >>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>> operators?
> >>>>>>
> >>>>>> I would strongly prefer the generic vector class to have the
> >>>>>> properties
> >>>>>> expected of any other generic container: copyable and assignable.  If
> >>>>>> we also want another vector type with this restriction I suggest
> >>>>>> to add
> >>>>>> another "noncopyable" type and make that property explicit in its
> >>>>>> name.
> >>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>
> >>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>> Looking around
> >>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
> >>>>> might be surprising (I added the move capability to match how vec<>
> >>>>> is used - as "reference" to a vector)
> >>>>
> >>>> The vec base classes are special: they have no ctors at all (because
> >>>> of their use in unions).  That's something we might have to live with
> >>>> but it's not a model to follow in ordinary containers.
> >>>
> >>> I don't think we have to live with it anymore, now that we're writing
> >>> C++11.
> >>>
> >>>> The auto_vec class was introduced to fill the need for a conventional
> >>>> sequence container with a ctor and dtor.  The missing copy ctor and
> >>>> assignment operators were an oversight, not a deliberate feature.
> >>>> This change fixes that oversight.
> >>>>
> >>>> The revised patch also adds a copy ctor/assignment to the auto_vec
> >>>> primary template (that's also missing it).  In addition, it adds
> >>>> a new class called auto_vec_ncopy that disables copying and
> >>>> assignment as you prefer.
> >>>
> >>> Hmm, adding another class doesn't really help with the confusion
> >>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>> which will still do a shallow copy.  I think it's probably better to
> >>> disable the copy special members for auto_vec until we fix vec<>.
> >>
> >> There are at least a couple of problems that get in the way of fixing
> >> all of vec to act like a well-behaved C++ container:
> >>
> >> 1) The embedded vec has a trailing "flexible" array member with its
> >> instances having different size.  They're initialized by memset and
> >> copied by memcpy.  The class can't have copy ctors or assignments
> >> but it should disable/delete them instead.
> >>
> >> 2) The heap-based vec is used throughout GCC with the assumption of
> >> shallow copy semantics (not just as function arguments but also as
> >> members of other such POD classes).  This can be changed by providing
> >> copy and move ctors and assignment operators for it, and also for
> >> some of the classes in which it's a member and that are used with
> >> the same assumption.
> >>
> >> 3) The heap-based vec::block_remove() assumes its elements are PODs.
> >> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >> and tree-vect-patterns.c).
> >>
> >> I took a stab at both and while (1) is easy, (2) is shaping up to
> >> be a big and tricky project.  Tricky because it involves using
> >> std::move in places where what's moved is subsequently still used.
> >> I can keep plugging away at it but it won't change the fact that
> >> the embedded and heap-based vecs have different requirements.
> >>
> >> It doesn't seem to me that having a safely copyable auto_vec needs
> >> to be put on hold until the rats nest above is untangled.  It won't
> >> make anything worse than it is.  (I have a project that depends on
> >> a sane auto_vec working).
> >>
> >> A couple of alternatives to solving this are to use std::vector or
> >> write an equivalent vector class just for GCC.
> >
> > It occurs to me that another way to work around the issue of passing an
> > auto_vec by value as a vec, and thus doing a shallow copy, would be to
> > add a vec ctor taking an auto_vec, and delete that.  This would mean if
> > you want to pass an auto_vec to a vec interface, it needs to be by
> > reference.  We might as well do the same for operator=, though that
> > isn't as important.
>
> Thanks, that sounds like a good idea.  Attached is an implementation
> of this change.  Since the auto_vec copy ctor and assignment have
> been deleted by someone else in the interim, this patch doesn't
> reverse that.  I will propose it separately after these changes
> are finalized.
>
> My approach was to 1) disable the auto_vec to vec conversion,
> 2) introduce an auto_vec::to_vec() to make the conversion possible
> explicitly, and 3) resolve compilation errors by either changing
> APIs to take a vec by reference or callers to convert auto_vec to
> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> improving the const-correctness of the APIs.
>
> When changing a vec API from by-value to by-reference I used vec &
> and didn't try to use vec * even though the latter seems to be more
> common (I avoided this to minimize the scope of changes).  If we
> want to do this I suggest handling that in a separate change.
>
> It's possible to get rid of vNULL in initialization.  It can be
> replaced with value-initialization in declarations but it's still
> handy when passing "empty" AKA nil vecs as arguments.  I didn't
> do it except in one instance (vec::copy) as a POC.
>
> I only touched APIs that needed to be adjusted so there may still
> be others that take vec by value that didn't change because they're
> not passed an auto_vec.  My hope is that we'll all pitch in and
> convert those over time.
>
> I kept an eye on the indirection due to changing vec to vec & that
> Richi's concerned about but I didn't look into the cost in any
> depth.  I don't have the sense that it's a significant issue.  In
> small static functions it shouldn't matter if they get inlined and
> in bigger ones I'd expect the cost of the indirection to be
> outweighed by other costs.  If there are cases where it should
> be felt to be significant I'll adjust those if you point thm out
> to me.

The cases I'm concerned about are when we for example
load from the vec<> in a loop but we can't hoist the extra
dereference because of aliasing issues (that is, the load
of the m_vec member).  It's enough for the loop to store
to a char * to make TBAA inefficient here.  At least the
situation with TBAA for pointers isn't as bad as it was a
few years ago (all pointers aliased - see get_alias_set
and the large comment before POINTER_TYPE_P
handling).  Still void * aliases all pointers.

From a performance perspective a direct load-to-load
dependence is always quite bad.

Richard.

> Tested on x86_64-linux.
>
> Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-25 22:36                   ` Martin Sebor
@ 2021-06-28  8:07                     ` Richard Biener
  2021-06-28 18:07                       ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-06-28  8:07 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/25/21 4:11 PM, Jason Merrill wrote:
> > On 6/25/21 4:51 PM, Martin Sebor wrote:
> >> On 6/1/21 3:38 PM, Jason Merrill wrote:
> >>> On 6/1/21 3:56 PM, Martin Sebor wrote:
> >>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
> >>>>>>> wrote:
> >>>>>>>>
> >>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>
> >>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
> >>>>>>>>>> the class manages its own memory but doesn't define (or delete)
> >>>>>>>>>> either special function.  Since I first ran into the problem,
> >>>>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>>>> assignment operator.
> >>>>>>>>>>
> >>>>>>>>>> The attached patch adds the two special functions to auto_vec
> >>>>>>>>>> along
> >>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>>>> containers
> >>>>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>>>> bootstrap
> >>>>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>>>
> >>>>>>>>> The question is whether we want such uses to appear since those
> >>>>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>>>> operators?
> >>>>>>>>
> >>>>>>>> I would strongly prefer the generic vector class to have the
> >>>>>>>> properties
> >>>>>>>> expected of any other generic container: copyable and
> >>>>>>>> assignable.  If
> >>>>>>>> we also want another vector type with this restriction I suggest
> >>>>>>>> to add
> >>>>>>>> another "noncopyable" type and make that property explicit in
> >>>>>>>> its name.
> >>>>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>>>
> >>>>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>>>> Looking around
> >>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
> >>>>>>> might be surprising (I added the move capability to match how vec<>
> >>>>>>> is used - as "reference" to a vector)
> >>>>>>
> >>>>>> The vec base classes are special: they have no ctors at all (because
> >>>>>> of their use in unions).  That's something we might have to live with
> >>>>>> but it's not a model to follow in ordinary containers.
> >>>>>
> >>>>> I don't think we have to live with it anymore, now that we're
> >>>>> writing C++11.
> >>>>>
> >>>>>> The auto_vec class was introduced to fill the need for a conventional
> >>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
> >>>>>> assignment operators were an oversight, not a deliberate feature.
> >>>>>> This change fixes that oversight.
> >>>>>>
> >>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
> >>>>>> primary template (that's also missing it).  In addition, it adds
> >>>>>> a new class called auto_vec_ncopy that disables copying and
> >>>>>> assignment as you prefer.
> >>>>>
> >>>>> Hmm, adding another class doesn't really help with the confusion
> >>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>>>> which will still do a shallow copy.  I think it's probably better
> >>>>> to disable the copy special members for auto_vec until we fix vec<>.
> >>>>
> >>>> There are at least a couple of problems that get in the way of fixing
> >>>> all of vec to act like a well-behaved C++ container:
> >>>>
> >>>> 1) The embedded vec has a trailing "flexible" array member with its
> >>>> instances having different size.  They're initialized by memset and
> >>>> copied by memcpy.  The class can't have copy ctors or assignments
> >>>> but it should disable/delete them instead.
> >>>>
> >>>> 2) The heap-based vec is used throughout GCC with the assumption of
> >>>> shallow copy semantics (not just as function arguments but also as
> >>>> members of other such POD classes).  This can be changed by providing
> >>>> copy and move ctors and assignment operators for it, and also for
> >>>> some of the classes in which it's a member and that are used with
> >>>> the same assumption.
> >>>>
> >>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
> >>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >>>> and tree-vect-patterns.c).
> >>>>
> >>>> I took a stab at both and while (1) is easy, (2) is shaping up to
> >>>> be a big and tricky project.  Tricky because it involves using
> >>>> std::move in places where what's moved is subsequently still used.
> >>>> I can keep plugging away at it but it won't change the fact that
> >>>> the embedded and heap-based vecs have different requirements.
> >>>>
> >>>> It doesn't seem to me that having a safely copyable auto_vec needs
> >>>> to be put on hold until the rats nest above is untangled.  It won't
> >>>> make anything worse than it is.  (I have a project that depends on
> >>>> a sane auto_vec working).
> >>>>
> >>>> A couple of alternatives to solving this are to use std::vector or
> >>>> write an equivalent vector class just for GCC.
> >>>
> >>> It occurs to me that another way to work around the issue of passing
> >>> an auto_vec by value as a vec, and thus doing a shallow copy, would
> >>> be to add a vec ctor taking an auto_vec, and delete that.  This would
> >>> mean if you want to pass an auto_vec to a vec interface, it needs to
> >>> be by reference.  We might as well do the same for operator=, though
> >>> that isn't as important.
> >>
> >> Thanks, that sounds like a good idea.  Attached is an implementation
> >> of this change.  Since the auto_vec copy ctor and assignment have
> >> been deleted by someone else in the interim, this patch doesn't
> >> reverse that.  I will propose it separately after these changes
> >> are finalized.
> >>
> >> My approach was to 1) disable the auto_vec to vec conversion,
> >> 2) introduce an auto_vec::to_vec() to make the conversion possible
> >> explicitly, and 3) resolve compilation errors by either changing
> >> APIs to take a vec by reference or callers to convert auto_vec to
> >> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> >> improving the const-correctness of the APIs.
> >
> > What did you base the choice between reference or to_vec on?  For
> > instance, it seems like c_parser_declaration_or_fndef could use a
> > reference, but you changed the callers instead.
>
> I went with a reference whenever I could.  That doesn't work when
> there are callers that pass in a vNULL, so there, and in assignments,
> I used to_vec().

Is there a way to "fix" the ugliness with vNULL?  All those functions
should be able to use const vec<>& as otherwise they'd leak memory?
Can't we pass vNULL to a const vec<>&?

Richard.

>
> Martin
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-28  8:07                     ` Richard Biener
@ 2021-06-28 18:07                       ` Martin Sebor
  2021-06-29 10:58                         ` Richard Biener
  2021-06-29 14:43                         ` [PATCH] " Jason Merrill
  0 siblings, 2 replies; 59+ messages in thread
From: Martin Sebor @ 2021-06-28 18:07 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On 6/28/21 2:07 AM, Richard Biener wrote:
> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 6/25/21 4:11 PM, Jason Merrill wrote:
>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>>> assignment operator.
>>>>>>>>>>>>
>>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
>>>>>>>>>>>> along
>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
>>>>>>>>>>>> containers
>>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>>> bootstrap
>>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>>
>>>>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>>> operators?
>>>>>>>>>>
>>>>>>>>>> I would strongly prefer the generic vector class to have the
>>>>>>>>>> properties
>>>>>>>>>> expected of any other generic container: copyable and
>>>>>>>>>> assignable.  If
>>>>>>>>>> we also want another vector type with this restriction I suggest
>>>>>>>>>> to add
>>>>>>>>>> another "noncopyable" type and make that property explicit in
>>>>>>>>>> its name.
>>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>>
>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
>>>>>>>>> Looking around
>>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>>>>>> might be surprising (I added the move capability to match how vec<>
>>>>>>>>> is used - as "reference" to a vector)
>>>>>>>>
>>>>>>>> The vec base classes are special: they have no ctors at all (because
>>>>>>>> of their use in unions).  That's something we might have to live with
>>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>>
>>>>>>> I don't think we have to live with it anymore, now that we're
>>>>>>> writing C++11.
>>>>>>>
>>>>>>>> The auto_vec class was introduced to fill the need for a conventional
>>>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>>>> This change fixes that oversight.
>>>>>>>>
>>>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>>> assignment as you prefer.
>>>>>>>
>>>>>>> Hmm, adding another class doesn't really help with the confusion
>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
>>>>>>> which will still do a shallow copy.  I think it's probably better
>>>>>>> to disable the copy special members for auto_vec until we fix vec<>.
>>>>>>
>>>>>> There are at least a couple of problems that get in the way of fixing
>>>>>> all of vec to act like a well-behaved C++ container:
>>>>>>
>>>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>>>> instances having different size.  They're initialized by memset and
>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>>> but it should disable/delete them instead.
>>>>>>
>>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>>>> shallow copy semantics (not just as function arguments but also as
>>>>>> members of other such POD classes).  This can be changed by providing
>>>>>> copy and move ctors and assignment operators for it, and also for
>>>>>> some of the classes in which it's a member and that are used with
>>>>>> the same assumption.
>>>>>>
>>>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>>> and tree-vect-patterns.c).
>>>>>>
>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>>> be a big and tricky project.  Tricky because it involves using
>>>>>> std::move in places where what's moved is subsequently still used.
>>>>>> I can keep plugging away at it but it won't change the fact that
>>>>>> the embedded and heap-based vecs have different requirements.
>>>>>>
>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>>>> make anything worse than it is.  (I have a project that depends on
>>>>>> a sane auto_vec working).
>>>>>>
>>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>>> write an equivalent vector class just for GCC.
>>>>>
>>>>> It occurs to me that another way to work around the issue of passing
>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This would
>>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
>>>>> be by reference.  We might as well do the same for operator=, though
>>>>> that isn't as important.
>>>>
>>>> Thanks, that sounds like a good idea.  Attached is an implementation
>>>> of this change.  Since the auto_vec copy ctor and assignment have
>>>> been deleted by someone else in the interim, this patch doesn't
>>>> reverse that.  I will propose it separately after these changes
>>>> are finalized.
>>>>
>>>> My approach was to 1) disable the auto_vec to vec conversion,
>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>>>> explicitly, and 3) resolve compilation errors by either changing
>>>> APIs to take a vec by reference or callers to convert auto_vec to
>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>>>> improving the const-correctness of the APIs.
>>>
>>> What did you base the choice between reference or to_vec on?  For
>>> instance, it seems like c_parser_declaration_or_fndef could use a
>>> reference, but you changed the callers instead.
>>
>> I went with a reference whenever I could.  That doesn't work when
>> there are callers that pass in a vNULL, so there, and in assignments,
>> I used to_vec().
> 
> Is there a way to "fix" the ugliness with vNULL?  All those functions
> should be able to use const vec<>& as otherwise they'd leak memory?
> Can't we pass vNULL to a const vec<>&?

vNULL can bind to a const vec& (via the vec conversion ctor) but
not to vec&.  The three functions that in the patch are passed
vNULL modify the argument when it's not vNULL but not otherwise.
An alternate design is to have them take a vec* and pass in
a plain NULL (or nullptr) instead of vNULL.  That would require
some surgery on the function bodies that I've been trying to
avoid in the first pass.

Functions that don't leak memory now shouldn't leak with these
changes, and conversely, those that do will still leak.  The patch
doesn't change that (as far as I know).

Going forward I think it's possible to replace most uses of vNULL
in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
can't be readily replaced are the ones where vNULL is passed as
an argument to functions taking a vec by value.  Those could be
changed to avoid vNULL too, but it would take a different approach
and more effort.  I'm not against it but I'd rather decouple those
changes from this already sizeable patch.

Martin

> 
> Richard.
> 
>>
>> Martin
>>


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-28 18:07                       ` Martin Sebor
@ 2021-06-29 10:58                         ` Richard Biener
  2021-06-29 11:34                           ` Martin Jambor
  2021-06-30  1:46                           ` Martin Sebor
  2021-06-29 14:43                         ` [PATCH] " Jason Merrill
  1 sibling, 2 replies; 59+ messages in thread
From: Richard Biener @ 2021-06-29 10:58 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/28/21 2:07 AM, Richard Biener wrote:
> > On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
> >>
> >> On 6/25/21 4:11 PM, Jason Merrill wrote:
> >>> On 6/25/21 4:51 PM, Martin Sebor wrote:
> >>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
> >>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
> >>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
> >>>>>>>>> wrote:
> >>>>>>>>>>
> >>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>>>
> >>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
> >>>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
> >>>>>>>>>>>> either special function.  Since I first ran into the problem,
> >>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>>>>>> assignment operator.
> >>>>>>>>>>>>
> >>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
> >>>>>>>>>>>> along
> >>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>>>>>> containers
> >>>>>>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>>>>>> bootstrap
> >>>>>>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>>>>>
> >>>>>>>>>>> The question is whether we want such uses to appear since those
> >>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>>>>>> operators?
> >>>>>>>>>>
> >>>>>>>>>> I would strongly prefer the generic vector class to have the
> >>>>>>>>>> properties
> >>>>>>>>>> expected of any other generic container: copyable and
> >>>>>>>>>> assignable.  If
> >>>>>>>>>> we also want another vector type with this restriction I suggest
> >>>>>>>>>> to add
> >>>>>>>>>> another "noncopyable" type and make that property explicit in
> >>>>>>>>>> its name.
> >>>>>>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>>>>>
> >>>>>>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>>>>>> Looking around
> >>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
> >>>>>>>>> might be surprising (I added the move capability to match how vec<>
> >>>>>>>>> is used - as "reference" to a vector)
> >>>>>>>>
> >>>>>>>> The vec base classes are special: they have no ctors at all (because
> >>>>>>>> of their use in unions).  That's something we might have to live with
> >>>>>>>> but it's not a model to follow in ordinary containers.
> >>>>>>>
> >>>>>>> I don't think we have to live with it anymore, now that we're
> >>>>>>> writing C++11.
> >>>>>>>
> >>>>>>>> The auto_vec class was introduced to fill the need for a conventional
> >>>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
> >>>>>>>> assignment operators were an oversight, not a deliberate feature.
> >>>>>>>> This change fixes that oversight.
> >>>>>>>>
> >>>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
> >>>>>>>> primary template (that's also missing it).  In addition, it adds
> >>>>>>>> a new class called auto_vec_ncopy that disables copying and
> >>>>>>>> assignment as you prefer.
> >>>>>>>
> >>>>>>> Hmm, adding another class doesn't really help with the confusion
> >>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>>>>>> which will still do a shallow copy.  I think it's probably better
> >>>>>>> to disable the copy special members for auto_vec until we fix vec<>.
> >>>>>>
> >>>>>> There are at least a couple of problems that get in the way of fixing
> >>>>>> all of vec to act like a well-behaved C++ container:
> >>>>>>
> >>>>>> 1) The embedded vec has a trailing "flexible" array member with its
> >>>>>> instances having different size.  They're initialized by memset and
> >>>>>> copied by memcpy.  The class can't have copy ctors or assignments
> >>>>>> but it should disable/delete them instead.
> >>>>>>
> >>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
> >>>>>> shallow copy semantics (not just as function arguments but also as
> >>>>>> members of other such POD classes).  This can be changed by providing
> >>>>>> copy and move ctors and assignment operators for it, and also for
> >>>>>> some of the classes in which it's a member and that are used with
> >>>>>> the same assumption.
> >>>>>>
> >>>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
> >>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >>>>>> and tree-vect-patterns.c).
> >>>>>>
> >>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
> >>>>>> be a big and tricky project.  Tricky because it involves using
> >>>>>> std::move in places where what's moved is subsequently still used.
> >>>>>> I can keep plugging away at it but it won't change the fact that
> >>>>>> the embedded and heap-based vecs have different requirements.
> >>>>>>
> >>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
> >>>>>> to be put on hold until the rats nest above is untangled.  It won't
> >>>>>> make anything worse than it is.  (I have a project that depends on
> >>>>>> a sane auto_vec working).
> >>>>>>
> >>>>>> A couple of alternatives to solving this are to use std::vector or
> >>>>>> write an equivalent vector class just for GCC.
> >>>>>
> >>>>> It occurs to me that another way to work around the issue of passing
> >>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
> >>>>> be to add a vec ctor taking an auto_vec, and delete that.  This would
> >>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
> >>>>> be by reference.  We might as well do the same for operator=, though
> >>>>> that isn't as important.
> >>>>
> >>>> Thanks, that sounds like a good idea.  Attached is an implementation
> >>>> of this change.  Since the auto_vec copy ctor and assignment have
> >>>> been deleted by someone else in the interim, this patch doesn't
> >>>> reverse that.  I will propose it separately after these changes
> >>>> are finalized.
> >>>>
> >>>> My approach was to 1) disable the auto_vec to vec conversion,
> >>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
> >>>> explicitly, and 3) resolve compilation errors by either changing
> >>>> APIs to take a vec by reference or callers to convert auto_vec to
> >>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> >>>> improving the const-correctness of the APIs.
> >>>
> >>> What did you base the choice between reference or to_vec on?  For
> >>> instance, it seems like c_parser_declaration_or_fndef could use a
> >>> reference, but you changed the callers instead.
> >>
> >> I went with a reference whenever I could.  That doesn't work when
> >> there are callers that pass in a vNULL, so there, and in assignments,
> >> I used to_vec().
> >
> > Is there a way to "fix" the ugliness with vNULL?  All those functions
> > should be able to use const vec<>& as otherwise they'd leak memory?
> > Can't we pass vNULL to a const vec<>&?
>
> vNULL can bind to a const vec& (via the vec conversion ctor) but
> not to vec&.  The three functions that in the patch are passed
> vNULL modify the argument when it's not vNULL but not otherwise.
> An alternate design is to have them take a vec* and pass in
> a plain NULL (or nullptr) instead of vNULL.  That would require
> some surgery on the function bodies that I've been trying to
> avoid in the first pass.

But I wonder if since you now identified them they could be massaged
prior to doing the change.

I do hope we end up not needing .to_vec () after all, if no users remain ;)

> Functions that don't leak memory now shouldn't leak with these
> changes, and conversely, those that do will still leak.  The patch
> doesn't change that (as far as I know).

It just occurs to me those cases could pass auto_vec<>() by reference instead
of vNULL?  So if the vector is modified then it's released afterwards?
That would fix the memleak.

> Going forward I think it's possible to replace most uses of vNULL
> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
> can't be readily replaced are the ones where vNULL is passed as
> an argument to functions taking a vec by value.  Those could be
> changed to avoid vNULL too, but it would take a different approach
> and more effort.  I'm not against it but I'd rather decouple those
> changes from this already sizeable patch.
>
> Martin
>
> >
> > Richard.
> >
> >>
> >> Martin
> >>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-29 10:58                         ` Richard Biener
@ 2021-06-29 11:34                           ` Martin Jambor
  2021-06-30  1:46                           ` Martin Sebor
  1 sibling, 0 replies; 59+ messages in thread
From: Martin Jambor @ 2021-06-29 11:34 UTC (permalink / raw)
  To: Richard Biener, Martin Sebor; +Cc: Jonathan Wakely, gcc-patches

Hi,

On Tue, Jun 29 2021, Richard Biener via Gcc-patches wrote:
> On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:

[...]

>>
>> vNULL can bind to a const vec& (via the vec conversion ctor) but
>> not to vec&.  The three functions that in the patch are passed
>> vNULL modify the argument when it's not vNULL but not otherwise.
>> An alternate design is to have them take a vec* and pass in
>> a plain NULL (or nullptr) instead of vNULL.  That would require
>> some surgery on the function bodies that I've been trying to
>> avoid in the first pass.
>
> But I wonder if since you now identified them they could be massaged
> prior to doing the change.
>
> I do hope we end up not needing .to_vec () after all, if no users remain ;)

I am afraid that the decay from ipa_auto_call_arg_values to
ipa_call_arg_values would still need them.

The auto variant is very useful for ipa-cp but the non-auto one is
necessary because of how ipa_cached_call_context is structured and how
it operates.

I tried to rework ipa_cached_call_context last summer - though I do not
remember it enough to be 100% sure that it would avoid the need for
to_vec - but Honza strongly preferred how it works now.

Martin


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-25 20:51               ` Martin Sebor
  2021-06-25 22:11                 ` Jason Merrill
  2021-06-28  8:05                 ` Richard Biener
@ 2021-06-29 12:30                 ` Trevor Saunders
  2 siblings, 0 replies; 59+ messages in thread
From: Trevor Saunders @ 2021-06-29 12:30 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, Richard Biener, Jonathan Wakely, gcc-patches

On Fri, Jun 25, 2021 at 02:51:58PM -0600, Martin Sebor via Gcc-patches wrote:
> On 6/1/21 3:38 PM, Jason Merrill wrote:
> > On 6/1/21 3:56 PM, Martin Sebor wrote:
> > > On 5/27/21 2:53 PM, Jason Merrill wrote:
> > > > On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> > > > > On 4/27/21 8:04 AM, Richard Biener wrote:
> > > > > > On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com> wrote:
> > > > > > > 
> > > > > > > On 4/27/21 1:58 AM, Richard Biener wrote:
> > > > > > > > On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> > > > > > > > <gcc-patches@gcc.gnu.org> wrote:
> > > > > > > > > 
> > > > > > > > > PR 90904 notes that auto_vec is unsafe to copy and assign because
> > > > > > > > > the class manages its own memory but doesn't define (or delete)
> > > > > > > > > either special function.  Since I first ran into the problem,
> > > > > > > > > auto_vec has grown a move ctor and move assignment from
> > > > > > > > > a dynamically-allocated vec but still no copy ctor or copy
> > > > > > > > > assignment operator.
> > > > > > > > > 
> > > > > > > > > The attached patch adds the two special functions to auto_vec along
> > > > > > > > > with a few simple tests.  It makes auto_vec
> > > > > > > > > safe to use in containers
> > > > > > > > > that expect copyable and assignable element
> > > > > > > > > types and passes bootstrap
> > > > > > > > > and regression testing on x86_64-linux.
> > > > > > > > 
> > > > > > > > The question is whether we want such uses to appear since those
> > > > > > > > can be quite inefficient?  Thus the option is to
> > > > > > > > delete those operators?
> > > > > > > 
> > > > > > > I would strongly prefer the generic vector class to
> > > > > > > have the properties
> > > > > > > expected of any other generic container: copyable and assignable.  If
> > > > > > > we also want another vector type with this
> > > > > > > restriction I suggest to add
> > > > > > > another "noncopyable" type and make that property
> > > > > > > explicit in its name.
> > > > > > > I can submit one in a followup patch if you think we need one.
> > > > > > 
> > > > > > I'm not sure (and not strictly against the copy and
> > > > > > assign). Looking around
> > > > > > I see that vec<> does not do deep copying.  Making auto_vec<> do it
> > > > > > might be surprising (I added the move capability to match how vec<>
> > > > > > is used - as "reference" to a vector)
> > > > > 
> > > > > The vec base classes are special: they have no ctors at all (because
> > > > > of their use in unions).  That's something we might have to live with
> > > > > but it's not a model to follow in ordinary containers.
> > > > 
> > > > I don't think we have to live with it anymore, now that we're
> > > > writing C++11.
> > > > 
> > > > > The auto_vec class was introduced to fill the need for a conventional
> > > > > sequence container with a ctor and dtor.  The missing copy ctor and
> > > > > assignment operators were an oversight, not a deliberate feature.
> > > > > This change fixes that oversight.
> > > > > 
> > > > > The revised patch also adds a copy ctor/assignment to the auto_vec
> > > > > primary template (that's also missing it).  In addition, it adds
> > > > > a new class called auto_vec_ncopy that disables copying and
> > > > > assignment as you prefer.
> > > > 
> > > > Hmm, adding another class doesn't really help with the confusion
> > > > richi mentions.  And many uses of auto_vec will pass them as
> > > > vec, which will still do a shallow copy.  I think it's probably
> > > > better to disable the copy special members for auto_vec until we
> > > > fix vec<>.
> > > 
> > > There are at least a couple of problems that get in the way of fixing
> > > all of vec to act like a well-behaved C++ container:
> > > 
> > > 1) The embedded vec has a trailing "flexible" array member with its
> > > instances having different size.  They're initialized by memset and
> > > copied by memcpy.  The class can't have copy ctors or assignments
> > > but it should disable/delete them instead.
> > > 
> > > 2) The heap-based vec is used throughout GCC with the assumption of
> > > shallow copy semantics (not just as function arguments but also as
> > > members of other such POD classes).  This can be changed by providing
> > > copy and move ctors and assignment operators for it, and also for
> > > some of the classes in which it's a member and that are used with
> > > the same assumption.
> > > 
> > > 3) The heap-based vec::block_remove() assumes its elements are PODs.
> > > That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> > > and tree-vect-patterns.c).
> > > 
> > > I took a stab at both and while (1) is easy, (2) is shaping up to
> > > be a big and tricky project.  Tricky because it involves using
> > > std::move in places where what's moved is subsequently still used.
> > > I can keep plugging away at it but it won't change the fact that
> > > the embedded and heap-based vecs have different requirements.
> > > 
> > > It doesn't seem to me that having a safely copyable auto_vec needs
> > > to be put on hold until the rats nest above is untangled.  It won't
> > > make anything worse than it is.  (I have a project that depends on
> > > a sane auto_vec working).
> > > 
> > > A couple of alternatives to solving this are to use std::vector or
> > > write an equivalent vector class just for GCC.
> > 
> > It occurs to me that another way to work around the issue of passing an
> > auto_vec by value as a vec, and thus doing a shallow copy, would be to
> > add a vec ctor taking an auto_vec, and delete that.  This would mean if
> > you want to pass an auto_vec to a vec interface, it needs to be by
> > reference.  We might as well do the same for operator=, though that
> > isn't as important.
> 
> Thanks, that sounds like a good idea.  Attached is an implementation
> of this change.  Since the auto_vec copy ctor and assignment have
> been deleted by someone else in the interim, this patch doesn't
> reverse that.  I will propose it separately after these changes
> are finalized.
> 
> My approach was to 1) disable the auto_vec to vec conversion,
> 2) introduce an auto_vec::to_vec() to make the conversion possible
> explicitly, and 3) resolve compilation errors by either changing
> APIs to take a vec by reference or callers to convert auto_vec to
> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> improving the const-correctness of the APIs.

In terms of naming, while I agree with Richi this would ideally just go
away, in the mean time as_vec seems like a clearer name to me, since its
more of an unsafe cast than a transfer of ownership to the return value.

The patch is very large, and while I tend to think its probably
reasonable, and it is largly mechanical, it would still be easier to
deal with if it was broken up, by the API being changed.  Changing some
of the functions to use array_slice would probably be better than const
vec &, and eliminate the concern about indirection by actually removing
one indirection which seems modestly worthwhile.

One other concern would be its still possible to do something like
auto_vec<int> x;
const vec<int> &y = x;
vec<int> z = y;

So it might be better to disable the conversion with a operator vec<> ()
on auto_vec that is deleted?

> When changing a vec API from by-value to by-reference I used vec &
> and didn't try to use vec * even though the latter seems to be more
> common (I avoided this to minimize the scope of changes).  If we
> want to do this I suggest handling that in a separate change.
> 
> It's possible to get rid of vNULL in initialization.  It can be
> replaced with value-initialization in declarations but it's still
> handy when passing "empty" AKA nil vecs as arguments.  I didn't
> do it except in one instance (vec::copy) as a POC.

 In principal it makes sense to do this, as much as it would be nice for
 the non gc vec to just go away.  However it adds unnecessary changes to
 a large mostly mechanical patch, so I think it would be better broken
 out into a separate patch.  While I believe it should work it certainly
 wouldn't be the first time this sort of change found a compiler bug, so
 you should probably at least test it with gcc 4.8 to see it handles it,
 and this increases the value of separating it from other changes?

> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index c4eb2b1c920..9841a320f89 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -1115,8 +1115,8 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask,
>     and have vector types, V0 has the same element type as V1, and the
>     number of elements the result is that of MASK.  */
>  tree
> -c_build_shufflevector (location_t loc, tree v0, tree v1, vec<tree> mask,
> -		       bool complain)
> +c_build_shufflevector (location_t loc, tree v0, tree v1,
> +		       const vec<tree> &mask, bool complain)
>  {
>    tree ret;
>    bool wrap = true;
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 88022d0b0a9..e43b12ae1dc 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -1049,7 +1049,7 @@ extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
>  extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note);
>  extern tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true);
>  extern tree c_build_shufflevector (location_t, tree, tree,
> -				   vec<tree>, bool = true);
> +				   const vec<tree> &, bool = true);
>  extern tree c_build_vec_convert (location_t, tree, location_t, tree, bool = true);
>  
>  extern void init_c_lex (void);
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 27034f88f49..e4a85eeb817 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -1780,7 +1780,7 @@ c_parser_external_declaration (c_parser *parser)
>      }
>  }
>  
> -static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
> +static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> &);
>  static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
>  
>  /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
> @@ -20325,12 +20325,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
>  	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
>  		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
>  	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
> -					 NULL, clauses);
> +					 NULL, clauses.to_vec ());

As an example of doing this piece by piece rather than as a mass change,
I suspect this could pass an array_slice, and I wonder if we could just
move the vec to the callee, c_finish_omp_declare_simd_clauses seems to
be the only user, and while a quick look doesn't answer the question, I
suspect from the name it should only be called once in
c_parser_declaration_or_fndecl, but that would take some investigation,
and I suppose can be done incrementally.

Trev


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-28 18:07                       ` Martin Sebor
  2021-06-29 10:58                         ` Richard Biener
@ 2021-06-29 14:43                         ` Jason Merrill
  2021-06-29 17:18                           ` Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-06-29 14:43 UTC (permalink / raw)
  To: Martin Sebor, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

On 6/28/21 2:07 PM, Martin Sebor wrote:
> On 6/28/21 2:07 AM, Richard Biener wrote:
>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>>>
>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign 
>>>>>>>>>>>>> because
>>>>>>>>>>>>> the class manages its own memory but doesn't define (or 
>>>>>>>>>>>>> delete)
>>>>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>>>> assignment operator.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
>>>>>>>>>>>>> along
>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
>>>>>>>>>>>>> containers
>>>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>>>> bootstrap
>>>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>>>
>>>>>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>>>> operators?
>>>>>>>>>>>
>>>>>>>>>>> I would strongly prefer the generic vector class to have the
>>>>>>>>>>> properties
>>>>>>>>>>> expected of any other generic container: copyable and
>>>>>>>>>>> assignable.  If
>>>>>>>>>>> we also want another vector type with this restriction I suggest
>>>>>>>>>>> to add
>>>>>>>>>>> another "noncopyable" type and make that property explicit in
>>>>>>>>>>> its name.
>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>>>
>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
>>>>>>>>>> Looking around
>>>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> 
>>>>>>>>>> do it
>>>>>>>>>> might be surprising (I added the move capability to match how 
>>>>>>>>>> vec<>
>>>>>>>>>> is used - as "reference" to a vector)
>>>>>>>>>
>>>>>>>>> The vec base classes are special: they have no ctors at all 
>>>>>>>>> (because
>>>>>>>>> of their use in unions).  That's something we might have to 
>>>>>>>>> live with
>>>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>>>
>>>>>>>> I don't think we have to live with it anymore, now that we're
>>>>>>>> writing C++11.
>>>>>>>>
>>>>>>>>> The auto_vec class was introduced to fill the need for a 
>>>>>>>>> conventional
>>>>>>>>> sequence container with a ctor and dtor.  The missing copy ctor 
>>>>>>>>> and
>>>>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>>>>> This change fixes that oversight.
>>>>>>>>>
>>>>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>>>> assignment as you prefer.
>>>>>>>>
>>>>>>>> Hmm, adding another class doesn't really help with the confusion
>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
>>>>>>>> which will still do a shallow copy.  I think it's probably better
>>>>>>>> to disable the copy special members for auto_vec until we fix 
>>>>>>>> vec<>.
>>>>>>>
>>>>>>> There are at least a couple of problems that get in the way of 
>>>>>>> fixing
>>>>>>> all of vec to act like a well-behaved C++ container:
>>>>>>>
>>>>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>>>>> instances having different size.  They're initialized by memset and
>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>>>> but it should disable/delete them instead.
>>>>>>>
>>>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>>>>> shallow copy semantics (not just as function arguments but also as
>>>>>>> members of other such POD classes).  This can be changed by 
>>>>>>> providing
>>>>>>> copy and move ctors and assignment operators for it, and also for
>>>>>>> some of the classes in which it's a member and that are used with
>>>>>>> the same assumption.
>>>>>>>
>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>>>> and tree-vect-patterns.c).
>>>>>>>
>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>>>> be a big and tricky project.  Tricky because it involves using
>>>>>>> std::move in places where what's moved is subsequently still used.
>>>>>>> I can keep plugging away at it but it won't change the fact that
>>>>>>> the embedded and heap-based vecs have different requirements.
>>>>>>>
>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>>>>> make anything worse than it is.  (I have a project that depends on
>>>>>>> a sane auto_vec working).
>>>>>>>
>>>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>>>> write an equivalent vector class just for GCC.
>>>>>>
>>>>>> It occurs to me that another way to work around the issue of passing
>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This would
>>>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
>>>>>> be by reference.  We might as well do the same for operator=, though
>>>>>> that isn't as important.
>>>>>
>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
>>>>> of this change.  Since the auto_vec copy ctor and assignment have
>>>>> been deleted by someone else in the interim, this patch doesn't
>>>>> reverse that.  I will propose it separately after these changes
>>>>> are finalized.
>>>>>
>>>>> My approach was to 1) disable the auto_vec to vec conversion,
>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>>>>> explicitly, and 3) resolve compilation errors by either changing
>>>>> APIs to take a vec by reference or callers to convert auto_vec to
>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>>>>> improving the const-correctness of the APIs.
>>>>
>>>> What did you base the choice between reference or to_vec on?  For
>>>> instance, it seems like c_parser_declaration_or_fndef could use a
>>>> reference, but you changed the callers instead.
>>>
>>> I went with a reference whenever I could.  That doesn't work when
>>> there are callers that pass in a vNULL, so there, and in assignments,
>>> I used to_vec().
>>
>> Is there a way to "fix" the ugliness with vNULL?  All those functions
>> should be able to use const vec<>& as otherwise they'd leak memory?
>> Can't we pass vNULL to a const vec<>&?
> 
> vNULL can bind to a const vec& (via the vec conversion ctor) but
> not to vec&.  The three functions that in the patch are passed
> vNULL modify the argument when it's not vNULL but not otherwise.

The c_parser_declaration_or_fndef case is rather ugly: the vec is passed 
by value, but then the modifications in c_finish_omp_declare_simd modify 
the original vec.

We could keep the same semantic problem and make it more blatant by 
changing to const vec& and doing a const_cast in 
c_finish_omp_declare_simd before modifying the vec.

Do the other two have the same problem?

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-29 14:43                         ` [PATCH] " Jason Merrill
@ 2021-06-29 17:18                           ` Martin Sebor
  2021-06-30  8:40                             ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-06-29 17:18 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener; +Cc: gcc-patches, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 9154 bytes --]

On 6/29/21 8:43 AM, Jason Merrill wrote:
> On 6/28/21 2:07 PM, Martin Sebor wrote:
>> On 6/28/21 2:07 AM, Richard Biener wrote:
>>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
>>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
>>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign 
>>>>>>>>>>>>>> because
>>>>>>>>>>>>>> the class manages its own memory but doesn't define (or 
>>>>>>>>>>>>>> delete)
>>>>>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>>>>> assignment operator.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
>>>>>>>>>>>>>> along
>>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
>>>>>>>>>>>>>> containers
>>>>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>>>>> bootstrap
>>>>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The question is whether we want such uses to appear since 
>>>>>>>>>>>>> those
>>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>>>>> operators?
>>>>>>>>>>>>
>>>>>>>>>>>> I would strongly prefer the generic vector class to have the
>>>>>>>>>>>> properties
>>>>>>>>>>>> expected of any other generic container: copyable and
>>>>>>>>>>>> assignable.  If
>>>>>>>>>>>> we also want another vector type with this restriction I 
>>>>>>>>>>>> suggest
>>>>>>>>>>>> to add
>>>>>>>>>>>> another "noncopyable" type and make that property explicit in
>>>>>>>>>>>> its name.
>>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>>>>
>>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
>>>>>>>>>>> Looking around
>>>>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> 
>>>>>>>>>>> do it
>>>>>>>>>>> might be surprising (I added the move capability to match how 
>>>>>>>>>>> vec<>
>>>>>>>>>>> is used - as "reference" to a vector)
>>>>>>>>>>
>>>>>>>>>> The vec base classes are special: they have no ctors at all 
>>>>>>>>>> (because
>>>>>>>>>> of their use in unions).  That's something we might have to 
>>>>>>>>>> live with
>>>>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>>>>
>>>>>>>>> I don't think we have to live with it anymore, now that we're
>>>>>>>>> writing C++11.
>>>>>>>>>
>>>>>>>>>> The auto_vec class was introduced to fill the need for a 
>>>>>>>>>> conventional
>>>>>>>>>> sequence container with a ctor and dtor.  The missing copy 
>>>>>>>>>> ctor and
>>>>>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>>>>>> This change fixes that oversight.
>>>>>>>>>>
>>>>>>>>>> The revised patch also adds a copy ctor/assignment to the 
>>>>>>>>>> auto_vec
>>>>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>>>>> assignment as you prefer.
>>>>>>>>>
>>>>>>>>> Hmm, adding another class doesn't really help with the confusion
>>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
>>>>>>>>> which will still do a shallow copy.  I think it's probably better
>>>>>>>>> to disable the copy special members for auto_vec until we fix 
>>>>>>>>> vec<>.
>>>>>>>>
>>>>>>>> There are at least a couple of problems that get in the way of 
>>>>>>>> fixing
>>>>>>>> all of vec to act like a well-behaved C++ container:
>>>>>>>>
>>>>>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>>>>>> instances having different size.  They're initialized by memset and
>>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>>>>> but it should disable/delete them instead.
>>>>>>>>
>>>>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>>>>>> shallow copy semantics (not just as function arguments but also as
>>>>>>>> members of other such POD classes).  This can be changed by 
>>>>>>>> providing
>>>>>>>> copy and move ctors and assignment operators for it, and also for
>>>>>>>> some of the classes in which it's a member and that are used with
>>>>>>>> the same assumption.
>>>>>>>>
>>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are 
>>>>>>>> PODs.
>>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>>>>> and tree-vect-patterns.c).
>>>>>>>>
>>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>>>>> be a big and tricky project.  Tricky because it involves using
>>>>>>>> std::move in places where what's moved is subsequently still used.
>>>>>>>> I can keep plugging away at it but it won't change the fact that
>>>>>>>> the embedded and heap-based vecs have different requirements.
>>>>>>>>
>>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>>>>>> make anything worse than it is.  (I have a project that depends on
>>>>>>>> a sane auto_vec working).
>>>>>>>>
>>>>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>>>>> write an equivalent vector class just for GCC.
>>>>>>>
>>>>>>> It occurs to me that another way to work around the issue of passing
>>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
>>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This 
>>>>>>> would
>>>>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
>>>>>>> be by reference.  We might as well do the same for operator=, though
>>>>>>> that isn't as important.
>>>>>>
>>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
>>>>>> of this change.  Since the auto_vec copy ctor and assignment have
>>>>>> been deleted by someone else in the interim, this patch doesn't
>>>>>> reverse that.  I will propose it separately after these changes
>>>>>> are finalized.
>>>>>>
>>>>>> My approach was to 1) disable the auto_vec to vec conversion,
>>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>>>>>> explicitly, and 3) resolve compilation errors by either changing
>>>>>> APIs to take a vec by reference or callers to convert auto_vec to
>>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>>>>>> improving the const-correctness of the APIs.
>>>>>
>>>>> What did you base the choice between reference or to_vec on?  For
>>>>> instance, it seems like c_parser_declaration_or_fndef could use a
>>>>> reference, but you changed the callers instead.
>>>>
>>>> I went with a reference whenever I could.  That doesn't work when
>>>> there are callers that pass in a vNULL, so there, and in assignments,
>>>> I used to_vec().
>>>
>>> Is there a way to "fix" the ugliness with vNULL?  All those functions
>>> should be able to use const vec<>& as otherwise they'd leak memory?
>>> Can't we pass vNULL to a const vec<>&?
>>
>> vNULL can bind to a const vec& (via the vec conversion ctor) but
>> not to vec&.  The three functions that in the patch are passed
>> vNULL modify the argument when it's not vNULL but not otherwise.
> 
> The c_parser_declaration_or_fndef case is rather ugly: the vec is passed 
> by value, but then the modifications in c_finish_omp_declare_simd modify 
> the original vec.
> 
> We could keep the same semantic problem and make it more blatant by 
> changing to const vec& and doing a const_cast in 
> c_finish_omp_declare_simd before modifying the vec.
> 
> Do the other two have the same problem?

Yes, the functions that take a vec by value and are passed an auto_vec
"by reference" (the result of to_vec()) modify the auto_vec.  This is
the "bug" this patch is designed to keep from happening by accident,
while letting the API clients do it intentionally.

Changing these APIs to take a const vec& while still letting them
modify the argument by casting away the constness seems even more
surprising to me than the current by-value style.

I do think it should be fixed but I'd have been more comfortable
handling that separately.  Attached is a (near) minimal change
along these lines to c_parser_declaration_or_fndef and its callers.
The logic isn't exactly the same as the original but no tests fail.
If this is the direction we want to go in I can see about making
an analogous change to the other two similar functions in the patch.
Let me know.

Martin

[-- Attachment #2: c-parser.c.diff --]
[-- Type: text/x-patch, Size: 9769 bytes --]

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 27034f88f49..b77e5b4f5c0 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *, vec<c_token>,
+					   bool, bool, tree * = NULL,
+					   vec<c_token> * = NULL,
 					   bool have_attrs = false,
 					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
@@ -1774,13 +1775,12 @@ c_parser_external_declaration (c_parser *parser)
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				     NULL, vNULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> &);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -1890,11 +1890,15 @@ static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration,
-			       vec<c_token> omp_declare_simd_clauses,
-			       bool have_attrs, tree attrs,
-			       struct oacc_routine_data *oacc_routine_data,
-			       bool *fallthru_attr_p)
+			       tree *objc_foreach_object_declaration
+			       /* = NULL */,
+			       vec<c_token> *omp_declare_simd_clauses
+			       /* = NULL */,
+			       bool have_attrs /* = false */,
+			       tree attrs /* = NULL_TREE */,
+			       struct oacc_routine_data *oacc_routine_data
+			       /* = NULL */,
+			       bool *fallthru_attr_p /* = NULL */)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -2150,9 +2154,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses)
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
-				       omp_declare_simd_clauses);
+				       *omp_declare_simd_clauses);
 	  if (oacc_routine_data)
 	    c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
@@ -2250,9 +2254,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		}
 	      else
 		{
@@ -2262,9 +2266,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		  init_loc = c_parser_peek_token (parser)->location;
 		  rich_location richloc (line_table, init_loc);
 		  start_init (d, asm_name, global_bindings_p (), &richloc);
@@ -2342,7 +2346,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      warn_parm_array_mismatch (lastloc, d, parms);
 		    }
 		}
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses)
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2360,7 +2364,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		  if (parms)
 		    temp_store_parm_decls (d, parms);
 		  c_finish_omp_declare_simd (parser, d, parms,
-					     omp_declare_simd_clauses);
+					     *omp_declare_simd_clauses);
 		  if (parms)
 		    temp_pop_parm_decls ();
 		}
@@ -2496,11 +2500,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL, vNULL);
+				       true, false);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses)
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
-				   omp_declare_simd_clauses);
+				   *omp_declare_simd_clauses);
       if (oacc_routine_data)
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       location_t startloc = c_parser_peek_token (parser)->location;
@@ -5699,7 +5703,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
-					 vNULL, have_std_attrs, std_attrs,
+					 NULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
 
 	  if (last_stmt && !fallthru_attr_p)
@@ -5731,7 +5735,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, vNULL);
+					     true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -6782,7 +6786,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression, vNULL);
+					 &object_expression);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -6813,7 +6817,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression, vNULL);
+					     true, &object_expression);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -11277,7 +11281,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL, vNULL);
+					   false, true);
 	  break;
 	}
     }
@@ -17273,12 +17277,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, false, NULL, &data);
+					 NULL, NULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, false, NULL, &data);
+				       NULL, NULL, false, NULL, &data);
     }
 }
 
@@ -18383,8 +18387,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
 	  this_pre_body = push_stmt_list ();
 	  c_in_omp_for = true;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, vNULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true);
 	  c_in_omp_for = false;
 	  if (this_pre_body)
 	    {
@@ -20325,12 +20328,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, &clauses);
       break;
     case pragma_struct:
     case pragma_param:
@@ -20351,7 +20354,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, &clauses);
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20360,7 +20363,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20841,7 +20844,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> &clauses)
 {
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-29 10:58                         ` Richard Biener
  2021-06-29 11:34                           ` Martin Jambor
@ 2021-06-30  1:46                           ` Martin Sebor
  2021-06-30  8:48                             ` Richard Biener
  2021-07-06 15:06                             ` [PING][PATCH] " Martin Sebor
  1 sibling, 2 replies; 59+ messages in thread
From: Martin Sebor @ 2021-06-30  1:46 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 10211 bytes --]

On 6/29/21 4:58 AM, Richard Biener wrote:
> On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 6/28/21 2:07 AM, Richard Biener wrote:
>>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
>>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
>>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
>>>>>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
>>>>>>>>>>>>>> either special function.  Since I first ran into the problem,
>>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>>>>> assignment operator.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
>>>>>>>>>>>>>> along
>>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
>>>>>>>>>>>>>> containers
>>>>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>>>>> bootstrap
>>>>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The question is whether we want such uses to appear since those
>>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>>>>> operators?
>>>>>>>>>>>>
>>>>>>>>>>>> I would strongly prefer the generic vector class to have the
>>>>>>>>>>>> properties
>>>>>>>>>>>> expected of any other generic container: copyable and
>>>>>>>>>>>> assignable.  If
>>>>>>>>>>>> we also want another vector type with this restriction I suggest
>>>>>>>>>>>> to add
>>>>>>>>>>>> another "noncopyable" type and make that property explicit in
>>>>>>>>>>>> its name.
>>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>>>>
>>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
>>>>>>>>>>> Looking around
>>>>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
>>>>>>>>>>> might be surprising (I added the move capability to match how vec<>
>>>>>>>>>>> is used - as "reference" to a vector)
>>>>>>>>>>
>>>>>>>>>> The vec base classes are special: they have no ctors at all (because
>>>>>>>>>> of their use in unions).  That's something we might have to live with
>>>>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>>>>
>>>>>>>>> I don't think we have to live with it anymore, now that we're
>>>>>>>>> writing C++11.
>>>>>>>>>
>>>>>>>>>> The auto_vec class was introduced to fill the need for a conventional
>>>>>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
>>>>>>>>>> assignment operators were an oversight, not a deliberate feature.
>>>>>>>>>> This change fixes that oversight.
>>>>>>>>>>
>>>>>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
>>>>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>>>>> assignment as you prefer.
>>>>>>>>>
>>>>>>>>> Hmm, adding another class doesn't really help with the confusion
>>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
>>>>>>>>> which will still do a shallow copy.  I think it's probably better
>>>>>>>>> to disable the copy special members for auto_vec until we fix vec<>.
>>>>>>>>
>>>>>>>> There are at least a couple of problems that get in the way of fixing
>>>>>>>> all of vec to act like a well-behaved C++ container:
>>>>>>>>
>>>>>>>> 1) The embedded vec has a trailing "flexible" array member with its
>>>>>>>> instances having different size.  They're initialized by memset and
>>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>>>>> but it should disable/delete them instead.
>>>>>>>>
>>>>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
>>>>>>>> shallow copy semantics (not just as function arguments but also as
>>>>>>>> members of other such POD classes).  This can be changed by providing
>>>>>>>> copy and move ctors and assignment operators for it, and also for
>>>>>>>> some of the classes in which it's a member and that are used with
>>>>>>>> the same assumption.
>>>>>>>>
>>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
>>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>>>>> and tree-vect-patterns.c).
>>>>>>>>
>>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>>>>> be a big and tricky project.  Tricky because it involves using
>>>>>>>> std::move in places where what's moved is subsequently still used.
>>>>>>>> I can keep plugging away at it but it won't change the fact that
>>>>>>>> the embedded and heap-based vecs have different requirements.
>>>>>>>>
>>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>>>>> to be put on hold until the rats nest above is untangled.  It won't
>>>>>>>> make anything worse than it is.  (I have a project that depends on
>>>>>>>> a sane auto_vec working).
>>>>>>>>
>>>>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>>>>> write an equivalent vector class just for GCC.
>>>>>>>
>>>>>>> It occurs to me that another way to work around the issue of passing
>>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
>>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This would
>>>>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
>>>>>>> be by reference.  We might as well do the same for operator=, though
>>>>>>> that isn't as important.
>>>>>>
>>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
>>>>>> of this change.  Since the auto_vec copy ctor and assignment have
>>>>>> been deleted by someone else in the interim, this patch doesn't
>>>>>> reverse that.  I will propose it separately after these changes
>>>>>> are finalized.
>>>>>>
>>>>>> My approach was to 1) disable the auto_vec to vec conversion,
>>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>>>>>> explicitly, and 3) resolve compilation errors by either changing
>>>>>> APIs to take a vec by reference or callers to convert auto_vec to
>>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>>>>>> improving the const-correctness of the APIs.
>>>>>
>>>>> What did you base the choice between reference or to_vec on?  For
>>>>> instance, it seems like c_parser_declaration_or_fndef could use a
>>>>> reference, but you changed the callers instead.
>>>>
>>>> I went with a reference whenever I could.  That doesn't work when
>>>> there are callers that pass in a vNULL, so there, and in assignments,
>>>> I used to_vec().
>>>
>>> Is there a way to "fix" the ugliness with vNULL?  All those functions
>>> should be able to use const vec<>& as otherwise they'd leak memory?
>>> Can't we pass vNULL to a const vec<>&?
>>
>> vNULL can bind to a const vec& (via the vec conversion ctor) but
>> not to vec&.  The three functions that in the patch are passed
>> vNULL modify the argument when it's not vNULL but not otherwise.
>> An alternate design is to have them take a vec* and pass in
>> a plain NULL (or nullptr) instead of vNULL.  That would require
>> some surgery on the function bodies that I've been trying to
>> avoid in the first pass.
> 
> But I wonder if since you now identified them they could be massaged
> prior to doing the change.
> 
> I do hope we end up not needing .to_vec () after all, if no users remain ;)

I'd be happy to if none remained.  I see how to eliminate those in
calls to functions like c_parser_declaration_or_fndef() (done in
the attached revision of the patch), but no easy way to get rid
of those that replace other implicit conversions, like all those
assignments to the vec members of the ipa_call_arg_values ctor.
If it's appropriate to std::move those then that would get rid
of the .to_vec () call.  I'm not familiar with the code but I
have the impression it might be meant more as a reference to
some "remote" object (an instance of ipa_auto_call_arg_values?)
If that's right then making the vec members auto_vec references
(or pointers) would be one way to "fix" this.

>> Functions that don't leak memory now shouldn't leak with these
>> changes, and conversely, those that do will still leak.  The patch
>> doesn't change that (as far as I know).
> 
> It just occurs to me those cases could pass auto_vec<>() by reference instead
> of vNULL?  So if the vector is modified then it's released afterwards?
> That would fix the memleak.

I see what you mean.  A function that modified the unnamed vec
temporary constructed from vNULL then the modified vector would
leak.  I don't think the functions the patch touches do that but
I've removed the vNULL conversion from all of them.  There are
many others that pass vNULL to a vec arguments that that the patch
doesn't touch but those would be worth a closer look at some point.

Attached is a revised patch with these changes (a superset of
those I sent in response to Jason's question), tested on x86_64.

Martin

> 
>> Going forward I think it's possible to replace most uses of vNULL
>> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
>> can't be readily replaced are the ones where vNULL is passed as
>> an argument to functions taking a vec by value.  Those could be
>> changed to avoid vNULL too, but it would take a different approach
>> and more effort.  I'm not against it but I'd rather decouple those
>> changes from this already sizeable patch.
>>
>> Martin
>>
>>>
>>> Richard.
>>>
>>>>
>>>> Martin
>>>>
>>


[-- Attachment #2: gcc-auto_vec-no-convert.diff --]
[-- Type: text/x-patch, Size: 75527 bytes --]

Disable implicit conversion from auto_vec to vec.


	* c-common.c (c_build_shufflevector): Adjust to vec change.
	* c-common.h (c_build_shufflevector): Same.

gcc/c/ChangeLog:

	* c-parser.c (c_finish_omp_declare_simd): Adjust to vec change.
	(c_parser_omp_declare_simd): Same.
	* c-tree.h (c_build_function_call_vec): Same.
	* c-typeck.c (c_build_function_call_vec): Same.

gcc/ChangeLog:

	* cfgloop.h (single_likely_exit): Adjust to vec change.
	* cfgloopanal.c (single_likely_exit): Same.
	* cgraph.h (struct cgraph_node): Same.
	* cgraphclones.c (cgraph_node::create_virtual_clone): Same.
	* dominance.c (prune_bbs_to_update_dominators): Same.
	(iterate_fix_dominators): Same.
	* dominance.h (iterate_fix_dominators): Same.
	* genautomata.c (merge_states): Same.
	* genextract.c (VEC_char_to_string): Same.
	* genmatch.c (dt_node::gen_kids_1): Same.
	(walk_captures): Same.
	* gimple-ssa-store-merging.c (check_no_overlap): Same.
	* gimple.c (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* gimple.h (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* haifa-sched.c (calc_priorities): Same.
	(haifa_sched_init): Same.
	(sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* ipa-cp.c (ipa_get_indirect_edge_target_1): Same.
	(adjust_callers_for_value_intersection): Same.
	(find_more_scalar_values_for_callers_subset): Same.
	(find_more_contexts_for_caller_subset): Same.
	(find_aggregate_values_for_callers_subset): Same.
	(copy_useful_known_contexts): Same.
	* ipa-fnsummary.c (remap_edge_summaries): Same.
	(remap_freqcounting_predicate): Same.
	* ipa-inline.c (add_new_edges_to_heap): Same.
	* ipa-predicate.c (predicate::remap_after_inlining): Same.
	* ipa-predicate.h:
	* ipa-prop.c (ipa_find_agg_cst_for_param): Same.
	* ipa-prop.h (ipa_find_agg_cst_for_param): Same.
	* ira-build.c (ira_loop_tree_body_rev_postorder): Same.
	* read-rtl.c (apply_iterators): Same.
	* rtl.h (native_decode_rtx): Same.
	(native_decode_vector_rtx): Same.
	* sched-int.h (sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* simplify-rtx.c (native_decode_vector_rtx): Same.
	(native_decode_rtx): Same.
	* tree-call-cdce.c (gen_shrink_wrap_conditions): Same.
	(shrink_wrap_one_built_in_call_with_conds): Same.
	(shrink_wrap_conditional_dead_built_in_calls): Same.
	* tree-data-ref.c (create_runtime_alias_checks): Same.
	(compute_all_dependences): Same.
	* tree-data-ref.h (compute_all_dependences): Same.
	(create_runtime_alias_checks): Same.
	(index_in_loop_nest): Same.
	* tree-if-conv.c (mask_exists): Same.
	* tree-loop-distribution.c (class loop_distribution): Same.
	(loop_distribution::create_rdg_vertices): Same.
	(dump_rdg_partitions): Same.
	(debug_rdg_partitions): Same.
	(partition_contains_all_rw): Same.
	(loop_distribution::distribute_loop): Same.
	* tree-parloops.c (oacc_entry_exit_ok_1): Same.
	(oacc_entry_exit_single_gang): Same.
	* tree-ssa-loop-im.c (hoist_memory_references): Same.
	(loop_suitable_for_sm): Same.
	* tree-ssa-loop-niter.c (bound_index): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (update_ops): Same.
	(swap_ops_for_binary_stmt): Same.
	(rewrite_expr_tree): Same.
	(rewrite_expr_tree_parallel): Same.
	* tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-sccvn.h (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-structalias.c (process_all_all_constraints): Same.
	(make_constraints_to): Same.
	(find_func_aliases_for_call): Same.
	(sort_fieldstack): Same.
	(check_for_overlaps): Same.
	* tree-vect-data-refs.c (vect_check_nonzero_value): Same.
	(vect_enhance_data_refs_alignment): Same.
	(vect_check_lower_bound): Same.
	(vect_prune_runtime_alias_test_list): Same.
	(vect_permute_store_chain): Same.
	* tree-vect-loop-manip.c (vect_create_cond_for_align_checks): Same.
	(vect_create_cond_for_unequal_addrs): Same.
	(vect_create_cond_for_lower_bounds): Same.
	(vect_create_cond_for_alias_checks): Same.
	* tree-vect-slp-patterns.c (vect_normalize_conj_loc): Same.
	(vect_validate_multiplication): Same.
	* tree-vect-slp.c (vect_analyze_slp_instance): Same.
	(vect_make_slp_decision): Same.
	(vect_slp_bbs): Same.
	(duplicate_and_interleave): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	* tree-vect-stmts.c (vect_create_vectorized_demotion_stmts): Same.
	* tree-vectorizer.h (vect_permute_store_chain): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	(duplicate_and_interleave): Same.
	* tree.c (build_vector_from_ctor): Same.
	(build_vector): Same.
	(check_vector_cst): Same.
	(check_vector_cst_duplicate): Same.
	(check_vector_cst_fill): Same.
	(check_vector_cst_stepped): Same.
	* tree.h (build_vector_from_ctor): Same.
	* vec.c (test_init): New.
	(vec_c_tests): Call test_init.
	* vec.h (struct vnull): Simplify.
	(auto_vec::to_vec): New member function.
	(vl_ptr>::copy): Use value initialization.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index c4eb2b1c920..9841a320f89 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1115,8 +1115,8 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask,
    and have vector types, V0 has the same element type as V1, and the
    number of elements the result is that of MASK.  */
 tree
-c_build_shufflevector (location_t loc, tree v0, tree v1, vec<tree> mask,
-		       bool complain)
+c_build_shufflevector (location_t loc, tree v0, tree v1,
+		       const vec<tree> &mask, bool complain)
 {
   tree ret;
   bool wrap = true;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 88022d0b0a9..e43b12ae1dc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1049,7 +1049,7 @@ extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
 extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note);
 extern tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true);
 extern tree c_build_shufflevector (location_t, tree, tree,
-				   vec<tree>, bool = true);
+				   const vec<tree> &, bool = true);
 extern tree c_build_vec_convert (location_t, tree, location_t, tree, bool = true);
 
 extern void init_c_lex (void);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 27034f88f49..b77e5b4f5c0 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *, vec<c_token>,
+					   bool, bool, tree * = NULL,
+					   vec<c_token> * = NULL,
 					   bool have_attrs = false,
 					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
@@ -1774,13 +1775,12 @@ c_parser_external_declaration (c_parser *parser)
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				     NULL, vNULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> &);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -1890,11 +1890,15 @@ static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration,
-			       vec<c_token> omp_declare_simd_clauses,
-			       bool have_attrs, tree attrs,
-			       struct oacc_routine_data *oacc_routine_data,
-			       bool *fallthru_attr_p)
+			       tree *objc_foreach_object_declaration
+			       /* = NULL */,
+			       vec<c_token> *omp_declare_simd_clauses
+			       /* = NULL */,
+			       bool have_attrs /* = false */,
+			       tree attrs /* = NULL_TREE */,
+			       struct oacc_routine_data *oacc_routine_data
+			       /* = NULL */,
+			       bool *fallthru_attr_p /* = NULL */)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -2150,9 +2154,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses)
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
-				       omp_declare_simd_clauses);
+				       *omp_declare_simd_clauses);
 	  if (oacc_routine_data)
 	    c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
@@ -2250,9 +2254,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		}
 	      else
 		{
@@ -2262,9 +2266,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		  init_loc = c_parser_peek_token (parser)->location;
 		  rich_location richloc (line_table, init_loc);
 		  start_init (d, asm_name, global_bindings_p (), &richloc);
@@ -2342,7 +2346,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      warn_parm_array_mismatch (lastloc, d, parms);
 		    }
 		}
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses)
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2360,7 +2364,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		  if (parms)
 		    temp_store_parm_decls (d, parms);
 		  c_finish_omp_declare_simd (parser, d, parms,
-					     omp_declare_simd_clauses);
+					     *omp_declare_simd_clauses);
 		  if (parms)
 		    temp_pop_parm_decls ();
 		}
@@ -2496,11 +2500,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL, vNULL);
+				       true, false);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses)
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
-				   omp_declare_simd_clauses);
+				   *omp_declare_simd_clauses);
       if (oacc_routine_data)
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       location_t startloc = c_parser_peek_token (parser)->location;
@@ -5699,7 +5703,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
-					 vNULL, have_std_attrs, std_attrs,
+					 NULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
 
 	  if (last_stmt && !fallthru_attr_p)
@@ -5731,7 +5735,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, vNULL);
+					     true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -6782,7 +6786,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression, vNULL);
+					 &object_expression);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -6813,7 +6817,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression, vNULL);
+					     true, &object_expression);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -11277,7 +11281,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL, vNULL);
+					   false, true);
 	  break;
 	}
     }
@@ -17273,12 +17277,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, false, NULL, &data);
+					 NULL, NULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, false, NULL, &data);
+				       NULL, NULL, false, NULL, &data);
     }
 }
 
@@ -18383,8 +18387,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
 	  this_pre_body = push_stmt_list ();
 	  c_in_omp_for = true;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, vNULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true);
 	  c_in_omp_for = false;
 	  if (this_pre_body)
 	    {
@@ -20325,12 +20328,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, &clauses);
       break;
     case pragma_struct:
     case pragma_param:
@@ -20351,7 +20354,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, &clauses);
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20360,7 +20363,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20841,7 +20844,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> &clauses)
 {
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a671a3eb740..ab6db3860f5 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -759,8 +759,9 @@ extern tree c_finish_omp_clauses (tree, enum c_omp_region_type);
 extern tree c_build_va_arg (location_t, tree, location_t, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
-extern tree c_build_function_call_vec (location_t, vec<location_t>, tree,
-				       vec<tree, va_gc> *, vec<tree, va_gc> *);
+extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
+				       tree, vec<tree, va_gc> *,
+				       vec<tree, va_gc> *);
 extern tree c_omp_clause_copy_ctor (tree, tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d079ce4b05b..efd4810b901 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3243,7 +3243,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 /* Like build_function_call_vec, but call also resolve_overloaded_builtin.  */
 
 tree
-c_build_function_call_vec (location_t loc, vec<location_t> arg_loc,
+c_build_function_call_vec (location_t loc, const vec<location_t> &arg_loc,
 			   tree function, vec<tree, va_gc> *params,
 			   vec<tree, va_gc> *origtypes)
 {
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 5e699276c88..5c2b98db9e5 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -385,7 +385,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
 
 extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
 extern edge single_exit (const class loop *);
-extern edge single_likely_exit (class loop *loop, vec<edge>);
+extern edge single_likely_exit (class loop *loop, const vec<edge> &);
 extern unsigned num_loop_branches (const class loop *);
 
 extern edge loop_preheader_edge (const class loop *);
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index 2db46c81036..4cd73c29776 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -470,7 +470,7 @@ mark_loop_exit_edges (void)
    to noreturn call.  */
 
 edge
-single_likely_exit (class loop *loop, vec<edge> exits)
+single_likely_exit (class loop *loop, const vec<edge> &exits)
 {
   edge found = single_exit (loop);
   unsigned i;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 9f4338fdf87..8c776d6f3a8 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -949,7 +949,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
   /* Create callgraph node clone with new declaration.  The actual body will be
      copied later at compilation stage.  The name of the new clone will be
      constructed from the name of the original node, SUFFIX and NUM_SUFFIX.  */
-  cgraph_node *create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+  cgraph_node *create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				     vec<ipa_replace_map *, va_gc> *tree_map,
 				     ipa_param_adjustments *param_adjustments,
 				     const char * suffix, unsigned num_suffix);
diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index 9f86463b42d..125f1b92862 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -567,7 +567,7 @@ clone_function_name (tree decl, const char *suffix)
    bitmap interface.
    */
 cgraph_node *
-cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+cgraph_node::create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				   vec<ipa_replace_map *, va_gc> *tree_map,
 				   ipa_param_adjustments *param_adjustments,
 				   const char * suffix, unsigned num_suffix)
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/genautomata.c b/gcc/genautomata.c
index 6bbfc684afa..e488c5f28ef 100644
--- a/gcc/genautomata.c
+++ b/gcc/genautomata.c
@@ -6137,7 +6137,7 @@ evaluate_equiv_classes (automaton_t automaton, vec<state_t> *equiv_classes)
 
 /* The function merges equivalent states of AUTOMATON.  */
 static void
-merge_states (automaton_t automaton, vec<state_t> equiv_classes)
+merge_states (automaton_t automaton, const vec<state_t> &equiv_classes)
 {
   state_t curr_state;
   state_t new_state;
diff --git a/gcc/genextract.c b/gcc/genextract.c
index 6fe4a2524fc..3ed2f6846c9 100644
--- a/gcc/genextract.c
+++ b/gcc/genextract.c
@@ -214,7 +214,7 @@ VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
    to a NUL-terminated string in malloc memory.  */
 static char *
-VEC_char_to_string (vec<char> v)
+VEC_char_to_string (const vec<char> &v)
 {
   size_t n = v.length ();
   char *s = XNEWVEC (char, n + 1);
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 4d476720c9e..dfd793d1f9b 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1628,8 +1628,9 @@ public:
 
   void gen_kids (FILE *, int, bool, int);
   void gen_kids_1 (FILE *, int, bool, int,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_operand *>,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_node *>);
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_node *> &);
 
   void analyze (sinfo_map_t &);
 };
@@ -2979,12 +2980,12 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
 
 void
 dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
-		     vec<dt_operand *> gimple_exprs,
-		     vec<dt_operand *> generic_exprs,
-		     vec<dt_operand *> fns,
-		     vec<dt_operand *> generic_fns,
-		     vec<dt_operand *> preds,
-		     vec<dt_node *> others)
+		     const vec<dt_operand *> &gimple_exprs,
+		     const vec<dt_operand *> &generic_exprs,
+		     const vec<dt_operand *> &fns,
+		     const vec<dt_operand *> &generic_fns,
+		     const vec<dt_operand *> &preds,
+		     const vec<dt_node *> &others)
 {
   char buf[128];
   char *kid_opname = buf;
@@ -5027,7 +5028,7 @@ parser::parse_pattern ()
    recursively.  */
 
 static void
-walk_captures (operand *op, vec<vec<capture *> > cpts)
+walk_captures (operand *op, vec<vec<capture *> > &cpts)
 {
   if (! op)
     return;
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 632947950e4..02ce068d9cf 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -2654,7 +2654,8 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
    go after the = _5 store and thus change behavior.  */
 
 static bool
-check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
+check_no_overlap (const vec<store_immediate_info *> &m_store_info,
+		  unsigned int i,
 		  bool all_integer_cst_p, unsigned int first_order,
 		  unsigned int last_order, unsigned HOST_WIDE_INT start,
 		  unsigned HOST_WIDE_INT end, unsigned int first_earlier,
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f1044e9c630..108daeda43b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -241,7 +241,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_vec (tree fn, vec<tree> args)
+gimple_build_call_vec (tree fn, const vec<tree> &args)
 {
   unsigned i;
   unsigned nargs = args.length ();
@@ -338,7 +338,7 @@ gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args)
+gimple_build_call_internal_vec (enum internal_fn fn, const vec<tree> &args)
 {
   unsigned i, nargs;
   gcall *call;
@@ -802,7 +802,7 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
    ARGS is a vector of labels excluding the default.  */
 
 gswitch *
-gimple_build_switch (tree index, tree default_label, vec<tree> args)
+gimple_build_switch (tree index, tree default_label, const vec<tree> &args)
 {
   unsigned i, nlabels = args.length ();
 
@@ -3049,7 +3049,7 @@ compare_case_labels (const void *p1, const void *p2)
 /* Sort the case labels in LABEL_VEC in place in ascending order.  */
 
 void
-sort_case_labels (vec<tree> label_vec)
+sort_case_labels (vec<tree> &label_vec)
 {
   label_vec.qsort (compare_case_labels);
 }
@@ -3074,7 +3074,7 @@ sort_case_labels (vec<tree> label_vec)
    found or not.  */
 
 void
-preprocess_case_label_vec_for_gimple (vec<tree> labels,
+preprocess_case_label_vec_for_gimple (vec<tree> &labels,
 				      tree index_type,
 				      tree *default_casep)
 {
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e7dc2a45a13..aabf68eaea0 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1516,11 +1516,11 @@ void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
-gcall *gimple_build_call_vec (tree, vec<tree> );
+gcall *gimple_build_call_vec (tree, const vec<tree> &);
 gcall *gimple_build_call (tree, unsigned, ...);
 gcall *gimple_build_call_valist (tree, unsigned, va_list);
 gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
-gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
+gcall *gimple_build_call_internal_vec (enum internal_fn, const vec<tree> &);
 gcall *gimple_build_call_from_tree (tree, tree);
 gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
@@ -1547,7 +1547,7 @@ gtry *gimple_build_try (gimple_seq, gimple_seq,
 gimple *gimple_build_wce (gimple_seq);
 gresx *gimple_build_resx (int);
 gswitch *gimple_build_switch_nlabels (unsigned, tree, tree);
-gswitch *gimple_build_switch (tree, tree, vec<tree> );
+gswitch *gimple_build_switch (tree, tree, const vec<tree> &);
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
@@ -1626,8 +1626,8 @@ extern bool nonbarrier_call_p (gimple *);
 extern bool infer_nonnull_range (gimple *, tree);
 extern bool infer_nonnull_range_by_dereference (gimple *, tree);
 extern bool infer_nonnull_range_by_attribute (gimple *, tree);
-extern void sort_case_labels (vec<tree>);
-extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
+extern void sort_case_labels (vec<tree> &);
+extern void preprocess_case_label_vec_for_gimple (vec<tree> &, tree, tree *);
 extern void gimple_seq_set_location (gimple_seq, location_t);
 extern void gimple_seq_discard (gimple_seq);
 extern void maybe_remove_unused_call_args (struct function *, gimple *);
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 9c88765d1fb..a166b706b8a 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -891,7 +891,7 @@ static void move_block_after_check (rtx_insn *);
 static void move_succs (vec<edge, va_gc> **, basic_block);
 static void sched_remove_insn (rtx_insn *);
 static void clear_priorities (rtx_insn *, rtx_vec_t *);
-static void calc_priorities (rtx_vec_t);
+static void calc_priorities (const rtx_vec_t &);
 static void add_jump_dependencies (rtx_insn *, rtx_insn *);
 
 #endif /* INSN_SCHEDULING */
@@ -7375,10 +7375,10 @@ haifa_sched_init (void)
     basic_block bb;
     FOR_EACH_BB_FN (bb, cfun)
       bbs.quick_push (bb);
-    sched_init_luids (bbs);
+    sched_init_luids (bbs.to_vec ());
     sched_deps_init (true);
     sched_extend_target ();
-    haifa_init_h_i_d (bbs);
+    haifa_init_h_i_d (bbs.to_vec ());
   }
 
   sched_init_only_bb = haifa_init_only_bb;
@@ -8923,7 +8923,7 @@ clear_priorities (rtx_insn *insn, rtx_vec_t *roots_ptr)
    changed.  ROOTS is a vector of instructions whose priority computation will
    trigger initialization of all cleared priorities.  */
 static void
-calc_priorities (rtx_vec_t roots)
+calc_priorities (const rtx_vec_t &roots)
 {
   int i;
   rtx_insn *insn;
@@ -8988,7 +8988,7 @@ sched_init_insn_luid (rtx_insn *insn)
    The hook common_sched_info->luid_for_non_insn () is used to determine
    if notes, labels, etc. need luids.  */
 void
-sched_init_luids (bb_vec_t bbs)
+sched_init_luids (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
@@ -9062,7 +9062,7 @@ init_h_i_d (rtx_insn *insn)
 
 /* Initialize haifa_insn_data for BBS.  */
 void
-haifa_init_h_i_d (bb_vec_t bbs)
+haifa_init_h_i_d (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 57c18af2bab..ce28ada19fe 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -2946,9 +2946,9 @@ propagate_constants_across_call (struct cgraph_edge *cs)
 
 static tree
 ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
-				vec<tree> known_csts,
-				vec<ipa_polymorphic_call_context> known_contexts,
-				vec<ipa_agg_value_set> known_aggs,
+				const vec<tree> &known_csts,
+				const vec<ipa_polymorphic_call_context> &known_contexts,
+				const vec<ipa_agg_value_set> &known_aggs,
 				struct ipa_agg_replacement_value *agg_reps,
 				bool *speculative)
 {
@@ -2985,7 +2985,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 	    }
 	  if (!t)
 	    {
-	      struct ipa_agg_value_set *agg;
+	      const ipa_agg_value_set *agg;
 	      if (known_aggs.length () > (unsigned int) param_index)
 		agg = &known_aggs[param_index];
 	      else
@@ -3045,7 +3045,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   if (!t && known_aggs.length () > (unsigned int) param_index
       && !ie->indirect_info->by_ref)
     {
-      struct ipa_agg_value_set *agg = &known_aggs[param_index];
+      const ipa_agg_value_set *agg = &known_aggs[param_index];
       t = ipa_find_agg_cst_for_param (agg,
 				      (unsigned) param_index
 					 < known_csts.length ()
@@ -4267,7 +4267,7 @@ get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
    this kind of adjustment is possible.  */
 
 static bool
-adjust_callers_for_value_intersection (vec<cgraph_edge *> callers,
+adjust_callers_for_value_intersection (vec<cgraph_edge *> &callers,
 				       cgraph_node *node)
 {
   for (unsigned i = 0; i < callers.length (); i++)
@@ -4725,8 +4725,8 @@ self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
 
 static void
 find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
-					    vec<tree> known_csts,
-					    vec<cgraph_edge *> callers)
+					    vec<tree> &known_csts,
+					    const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -4818,7 +4818,7 @@ static void
 find_more_contexts_for_caller_subset (cgraph_node *node,
 				      vec<ipa_polymorphic_call_context>
 				      *known_contexts,
-				      vec<cgraph_edge *> callers)
+				      const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -5179,7 +5179,7 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
 
 static struct ipa_agg_replacement_value *
 find_aggregate_values_for_callers_subset (struct cgraph_node *node,
-					  vec<cgraph_edge *> callers)
+					  const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *dest_info = ipa_node_params_sum->get (node);
   struct ipa_agg_replacement_value *res;
@@ -5413,7 +5413,7 @@ known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts)
 /* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL.  */
 
 static vec<ipa_polymorphic_call_context>
-copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts)
+copy_useful_known_contexts (const vec<ipa_polymorphic_call_context> &known_contexts)
 {
   if (known_contexts_useful_p (known_contexts))
     return known_contexts.copy ();
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 95d28757f95..cf80ce3c040 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -3967,8 +3967,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 		      class ipa_fn_summary *info,
 		      class ipa_node_params *params_summary,
 		      class ipa_fn_summary *callee_info,
-		      vec<int> operand_map,
-		      vec<HOST_WIDE_INT> offset_map,
+		      const vec<int> &operand_map,
+		      const vec<HOST_WIDE_INT> &offset_map,
 		      clause_t possible_truths,
 		      predicate *toplev_predicate)
 {
@@ -4028,8 +4028,8 @@ remap_freqcounting_predicate (class ipa_fn_summary *info,
 			      class ipa_node_params *params_summary,
 			      class ipa_fn_summary *callee_info,
 			      vec<ipa_freqcounting_predicate, va_gc> *v,
-			      vec<int> operand_map,
-			      vec<HOST_WIDE_INT> offset_map,
+			      const vec<int> &operand_map,
+			      const vec<HOST_WIDE_INT> &offset_map,
 			      clause_t possible_truths,
 			      predicate *toplev_predicate)
 
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 9d896beb2ac..413446bcc46 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1774,7 +1774,7 @@ compute_max_insns (cgraph_node *node, int insns)
 /* Compute badness of all edges in NEW_EDGES and add them to the HEAP.  */
 
 static void
-add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
+add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> &new_edges)
 {
   while (new_edges.length () > 0)
     {
diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c
index 6dd749b8ffa..e4b11ec3ae3 100644
--- a/gcc/ipa-predicate.c
+++ b/gcc/ipa-predicate.c
@@ -507,8 +507,8 @@ predicate
 predicate::remap_after_inlining (class ipa_fn_summary *info,
 				 class ipa_node_params *params_summary,
 				 class ipa_fn_summary *callee_info,
-				 vec<int> operand_map,
-				 vec<HOST_WIDE_INT> offset_map,
+				 const vec<int> &operand_map,
+				 const vec<HOST_WIDE_INT> &offset_map,
 				 clause_t possible_truths,
 				 const predicate &toplev_predicate)
 {
diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h
index 3ed71046c0c..ac52b54aa36 100644
--- a/gcc/ipa-predicate.h
+++ b/gcc/ipa-predicate.h
@@ -243,7 +243,7 @@ public:
   predicate remap_after_inlining (class ipa_fn_summary *,
 		  		  class ipa_node_params *params_summary,
 			          class ipa_fn_summary *,
-				  vec<int>, vec<HOST_WIDE_INT>,
+				  const vec<int> &, const vec<HOST_WIDE_INT> &,
 				  clause_t, const predicate &);
 
   void stream_in (class lto_input_block *);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index f74d2e17b69..43f46a578c6 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -3562,7 +3562,7 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
    initializer of a constant.  */
 
 tree
-ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 			    HOST_WIDE_INT offset, bool by_ref,
 			    bool *from_global_constant)
 {
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 3d28a6e8640..d1cd42263f5 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
@@ -1092,7 +1092,7 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value,
 void ipa_analyze_node (struct cgraph_node *);
 
 /* Aggregate jump function related functions.  */
-tree ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 				 HOST_WIDE_INT offset, bool by_ref,
 				 bool *from_global_constant = NULL);
 bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 4031ce18287..42120656366 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -1672,7 +1672,7 @@ finish_cost_vectors (void)
 
 static vec<ira_loop_tree_node_t>
 ira_loop_tree_body_rev_postorder (ira_loop_tree_node_t loop_node ATTRIBUTE_UNUSED,
-				  vec<ira_loop_tree_node_t> loop_preorder)
+				  const vec<ira_loop_tree_node_t> &loop_preorder)
 {
   vec<ira_loop_tree_node_t> topsort_nodes = vNULL;
   unsigned int n_loop_preorder;
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925402877ec..c6dfed80e04 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -835,7 +835,7 @@ md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
    gives the iterator associated with argument I of ONAME.  */
 
 static void
-add_overload_instance (overloaded_name *oname, vec<mapping *> iterators, rtx x)
+add_overload_instance (overloaded_name *oname, vec<mapping *> &iterators, rtx x)
 {
   /* Create the instance.  */
   overloaded_instance *instance = new overloaded_instance;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 5ed0d6dd6fa..2faf4ac4f97 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2416,9 +2416,9 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
 			       struct full_rtx_costs *);
 extern bool native_encode_rtx (machine_mode, rtx, vec<target_unit> &,
 			       unsigned int, unsigned int);
-extern rtx native_decode_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_rtx (machine_mode, const vec<target_unit> &,
 			      unsigned int);
-extern rtx native_decode_vector_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_vector_rtx (machine_mode, const vec<target_unit> &,
 				     unsigned int, unsigned int, unsigned int);
 extern poly_uint64 subreg_lsb (const_rtx);
 extern poly_uint64 subreg_size_lsb (poly_uint64, poly_uint64, poly_uint64);
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 4727ab28920..868f1eb6c89 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -43,12 +43,12 @@ extern void sched_init_bbs (void);
 
 extern void sched_extend_luids (void);
 extern void sched_init_insn_luid (rtx_insn *);
-extern void sched_init_luids (bb_vec_t);
+extern void sched_init_luids (const bb_vec_t &);
 extern void sched_finish_luids (void);
 
 extern void sched_extend_target (void);
 
-extern void haifa_init_h_i_d (bb_vec_t);
+extern void haifa_init_h_i_d (const bb_vec_t &);
 extern void haifa_finish_h_i_d (void);
 
 /* Hooks that are common to all the schedulers.  */
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index c82101c73a4..113991ddff4 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -6742,7 +6742,7 @@ native_encode_rtx (machine_mode mode, rtx x, vec<target_unit> &bytes,
    Return the vector on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_vector_rtx (machine_mode mode, const vec<target_unit> &bytes,
 			  unsigned int first_byte, unsigned int npatterns,
 			  unsigned int nelts_per_pattern)
 {
@@ -6787,7 +6787,7 @@ native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
    Return the rtx on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_rtx (machine_mode mode, const vec<target_unit> &bytes,
 		   unsigned int first_byte)
 {
   if (VECTOR_MODE_P (mode))
diff --git a/gcc/tree-call-cdce.c b/gcc/tree-call-cdce.c
index 666839755d0..d9b9b4c6e84 100644
--- a/gcc/tree-call-cdce.c
+++ b/gcc/tree-call-cdce.c
@@ -761,7 +761,7 @@ get_no_error_domain (enum built_in_function fnc)
    condition are separated by NULL tree in the vector.  */
 
 static void
-gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
+gen_shrink_wrap_conditions (gcall *bi_call, const vec<gimple *> &conds,
                             unsigned int *nconds)
 {
   gcall *call;
@@ -797,7 +797,8 @@ gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
    when it is non-null, it is called while all of the CONDS are true.  */
 
 static void
-shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
+shrink_wrap_one_built_in_call_with_conds (gcall *bi_call,
+					  const vec <gimple *> &conds,
 					  unsigned int nconds,
 					  gcall *bi_newcall = NULL)
 {
@@ -1132,7 +1133,7 @@ use_internal_fn (gcall *call)
    wrapping transformation.  */
 
 static void
-shrink_wrap_conditional_dead_built_in_calls (vec<gcall *> calls)
+shrink_wrap_conditional_dead_built_in_calls (const vec<gcall *> &calls)
 {
   unsigned i = 0;
 
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b6abd8b8de7..210ac2851a5 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -2643,7 +2643,7 @@ create_intersect_range_checks (class loop *loop, tree *cond_expr,
 
 void
 create_runtime_alias_checks (class loop *loop,
-			     vec<dr_with_seg_len_pair_t> *alias_pairs,
+			     const vec<dr_with_seg_len_pair_t> *alias_pairs,
 			     tree * cond_expr)
 {
   tree part_cond_expr;
@@ -5635,9 +5635,9 @@ compute_affine_dependence (struct data_dependence_relation *ddr,
    is small enough to be handled.  */
 
 bool
-compute_all_dependences (vec<data_reference_p> datarefs,
+compute_all_dependences (const vec<data_reference_p> &datarefs,
 			 vec<ddr_p> *dependence_relations,
-			 vec<loop_p> loop_nest,
+			 const vec<loop_p> &loop_nest,
 			 bool compute_self_and_rr)
 {
   struct data_dependence_relation *ddr;
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8001cc54f51..a0ff2a80263 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -551,9 +551,9 @@ extern struct data_dependence_relation *initialize_data_dependence_relation
 extern void compute_affine_dependence (struct data_dependence_relation *,
 				       loop_p);
 extern void compute_self_dependence (struct data_dependence_relation *);
-extern bool compute_all_dependences (vec<data_reference_p> ,
+extern bool compute_all_dependences (const vec<data_reference_p> &,
 				     vec<ddr_p> *,
-				     vec<loop_p>, bool);
+				     const vec<loop_p> &, bool);
 extern tree find_data_references_in_bb (class loop *, basic_block,
                                         vec<data_reference_p> *);
 extern unsigned int dr_alignment (innermost_loop_behavior *);
@@ -578,7 +578,8 @@ extern int data_ref_compare_tree (tree, tree);
 extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
 					   poly_uint64);
 extern void create_runtime_alias_checks (class loop *,
-					 vec<dr_with_seg_len_pair_t> *, tree*);
+					 const vec<dr_with_seg_len_pair_t> *,
+					 tree*);
 extern tree dr_direction_indicator (struct data_reference *);
 extern tree dr_zero_step_indicator (struct data_reference *);
 extern bool dr_known_forward_stride_p (struct data_reference *);
@@ -666,7 +667,7 @@ ddr_dependence_level (ddr_p ddr)
 /* Return the index of the variable VAR in the LOOP_NEST array.  */
 
 static inline int
-index_in_loop_nest (int var, vec<loop_p> loop_nest)
+index_in_loop_nest (int var, const vec<loop_p> &loop_nest)
 {
   class loop *loopi;
   int var_index;
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 345488e2a19..49e89cffa1a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -2208,7 +2208,7 @@ insert_gimplified_predicates (loop_p loop)
    mask if it was created for given SIZE and -1 otherwise.  */
 
 static int
-mask_exists (int size, vec<int> vec)
+mask_exists (int size, const vec<int> &vec)
 {
   unsigned int ix;
   int v;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 65aa1df4aba..7b715d684f5 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -527,7 +527,7 @@ class loop_distribution
 
   /* Build the vertices of the reduced dependence graph RDG.  Return false
      if that failed.  */
-  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts, loop_p loop);
+  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> &stmts, loop_p loop);
 
   /* Initialize STMTS with all the statements of LOOP.  We use topological
      order to discover all statements.  The order is important because
@@ -646,7 +646,7 @@ class loop_distribution
      statements from STMTS into separate loops.  Returns the number of
      distributed loops.  Set NB_CALLS to number of generated builtin calls.
      Set *DESTROY_P to whether LOOP needs to be destroyed.  */
-  int distribute_loop (class loop *loop, vec<gimple *> stmts,
+  int distribute_loop (class loop *loop, const vec<gimple *> &stmts,
 		       control_dependences *cd, int *nb_calls, bool *destroy_p,
 		       bool only_patterns_p);
 
@@ -699,7 +699,7 @@ bb_top_order_cmp_r (const void *x, const void *y, void *loop)
 }
 
 bool
-loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts,
+loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> &stmts,
 					loop_p loop)
 {
   int i;
@@ -1953,7 +1953,7 @@ loop_distribution::rdg_build_partitions (struct graph *rdg,
 /* Dump to FILE the PARTITIONS.  */
 
 static void
-dump_rdg_partitions (FILE *file, vec<partition *> partitions)
+dump_rdg_partitions (FILE *file, const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -1963,10 +1963,10 @@ dump_rdg_partitions (FILE *file, vec<partition *> partitions)
 }
 
 /* Debug PARTITIONS.  */
-extern void debug_rdg_partitions (vec<partition *> );
+extern void debug_rdg_partitions (const vec<partition *> &);
 
 DEBUG_FUNCTION void
-debug_rdg_partitions (vec<partition *> partitions)
+debug_rdg_partitions (const vec<partition *> &partitions)
 {
   dump_rdg_partitions (stderr, partitions);
 }
@@ -2017,7 +2017,7 @@ number_of_rw_in_partition (struct graph *rdg, partition *partition)
 
 static bool
 partition_contains_all_rw (struct graph *rdg,
-			   vec<partition *> partitions)
+			   const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -2921,7 +2921,8 @@ loop_distribution::finalize_partitions (class loop *loop,
    Set *DESTROY_P to whether LOOP needs to be destroyed.  */
 
 int
-loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts,
+loop_distribution::distribute_loop (class loop *loop,
+		 const vec<gimple *> &stmts,
 		 control_dependences *cd, int *nb_calls, bool *destroy_p,
 		 bool only_patterns_p)
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index fe1baef32a7..bb547572653 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -3713,7 +3713,7 @@ ref_conflicts_with_region (gimple_stmt_iterator gsi, ao_ref *ref,
    reduction results in REDUCTION_STORES.  */
 
 static bool
-oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_ok_1 (bitmap in_loop_bbs, const vec<basic_block> &region_bbs,
 		      reduction_info_table_type *reduction_list,
 		      bitmap reduction_stores)
 {
@@ -3828,7 +3828,8 @@ oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
    if any changes were made.  */
 
 static bool
-oacc_entry_exit_single_gang (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_single_gang (bitmap in_loop_bbs,
+			     const vec<basic_block> &region_bbs,
 			     bitmap reduction_stores)
 {
   tree gang_pos = NULL_TREE;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 7de47edbcb3..c778f7e87fd 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -2511,7 +2511,7 @@ sm_seq_valid_bb (class loop *loop, basic_block bb, tree vdef,
 
 static void
 hoist_memory_references (class loop *loop, bitmap mem_refs,
-			 vec<edge> exits)
+			 const vec<edge> &exits)
 {
   im_mem_ref *ref;
   unsigned  i;
@@ -2906,7 +2906,7 @@ find_refs_for_sm (class loop *loop, bitmap sm_executed, bitmap refs_to_sm)
 
 static bool
 loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
-		      vec<edge> exits)
+		      const vec<edge> &exits)
 {
   unsigned i;
   edge ex;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index b5add827018..3f9954c88a3 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3929,7 +3929,7 @@ wide_int_cmp (const void *p1, const void *p2)
    Lookup by binary search.  */
 
 static int
-bound_index (vec<widest_int> bounds, const widest_int &bound)
+bound_index (const vec<widest_int> &bounds, const widest_int &bound)
 {
   unsigned int end = bounds.length ();
   unsigned int begin = 0;
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index d86fe26bd07..a715cddc13d 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3100,7 +3100,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    vec<pre_expr> avail)
+			    vec<pre_expr> &avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 2dd4435b981..8498cfc7aa8 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -4486,7 +4486,7 @@ get_ops (tree var, enum tree_code code, vec<operand_entry *> *ops,
    stmts.  */
 
 static tree
-update_ops (tree var, enum tree_code code, vec<operand_entry *> ops,
+update_ops (tree var, enum tree_code code, const vec<operand_entry *> &ops,
 	    unsigned int *pidx, class loop *loop)
 {
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5033,7 +5033,7 @@ remove_visited_stmt_chain (tree var)
    cases, but it is unlikely to be worth it.  */
 
 static void
-swap_ops_for_binary_stmt (vec<operand_entry *> ops,
+swap_ops_for_binary_stmt (const vec<operand_entry *> &ops,
 			  unsigned int opindex, gimple *stmt)
 {
   operand_entry *oe1, *oe2, *oe3;
@@ -5104,7 +5104,8 @@ insert_stmt_before_use (gimple *stmt, gimple *stmt_to_insert)
 
 static tree
 rewrite_expr_tree (gimple *stmt, enum tree_code rhs_code, unsigned int opindex,
-		   vec<operand_entry *> ops, bool changed, bool next_changed)
+		   const vec<operand_entry *> &ops, bool changed,
+		   bool next_changed)
 {
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -5326,7 +5327,7 @@ get_reassociation_width (int ops_num, enum tree_code opc,
 
 static void
 rewrite_expr_tree_parallel (gassign *stmt, int width,
-			    vec<operand_entry *> ops)
+			    const vec<operand_entry *> &ops)
 {
   enum tree_code opcode = gimple_assign_rhs_code (stmt);
   int op_num = ops.length ();
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 64e3a707f5c..3451ff1f157 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1040,9 +1040,8 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
 bool
 ao_ref_init_from_vn_reference (ao_ref *ref,
 			       alias_set_type set, alias_set_type base_set,
-			       tree type, vec<vn_reference_op_s> ops)
+			       tree type, const vec<vn_reference_op_s> &ops)
 {
-  vn_reference_op_t op;
   unsigned i;
   tree base = NULL_TREE;
   tree *op0_p = &base;
@@ -1061,7 +1060,10 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
     size = wi::to_poly_offset (size_tree);
 
   /* Lower the final access size from the outermost expression.  */
-  op = &ops[0];
+  const_vn_reference_op_t cst_op = &ops[0];
+  /* Cast away constness for the sake of the const-unsafe
+     FOR_EACH_VEC_ELT().  */
+  vn_reference_op_t op = const_cast<vn_reference_op_t>(cst_op);
   size_tree = NULL_TREE;
   if (op->opcode == COMPONENT_REF)
     size_tree = DECL_SIZE (op->op0);
@@ -1092,7 +1094,7 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
 	      && op->op0
 	      && DECL_P (TREE_OPERAND (op->op0, 0)))
 	    {
-	      vn_reference_op_t pop = &ops[i-1];
+	      const_vn_reference_op_t pop = &ops[i-1];
 	      base = TREE_OPERAND (op->op0, 0);
 	      if (known_eq (pop->off, -1))
 		{
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 6df526c269b..96100596d2e 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -254,7 +254,7 @@ tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
 vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
 				       tree, tree *, tree, unsigned int);
 bool ao_ref_init_from_vn_reference (ao_ref *, alias_set_type, alias_set_type,
-				    tree, vec<vn_reference_op_s> );
+				    tree, const vec<vn_reference_op_s> &);
 vec<vn_reference_op_s> vn_reference_operands_for_lookup (tree);
 tree vn_reference_lookup_pieces (tree, alias_set_type, alias_set_type, tree,
 				 vec<vn_reference_op_s> ,
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 7163438e23d..e8e35362062 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3713,8 +3713,8 @@ get_constraint_for_rhs (tree t, vec<ce_s> *results)
    entries in *LHSC.  */
 
 static void
-process_all_all_constraints (vec<ce_s> lhsc,
-			     vec<ce_s> rhsc)
+process_all_all_constraints (const vec<ce_s> &lhsc,
+			     const vec<ce_s> &rhsc)
 {
   struct constraint_expr *lhsp, *rhsp;
   unsigned i, j;
@@ -3814,7 +3814,7 @@ do_structure_copy (tree lhsop, tree rhsop)
 /* Create constraints ID = { rhsc }.  */
 
 static void
-make_constraints_to (unsigned id, vec<ce_s> rhsc)
+make_constraints_to (unsigned id, const vec<ce_s> &rhsc)
 {
   struct constraint_expr *c;
   struct constraint_expr includes;
@@ -4158,7 +4158,7 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
    the LHS point to global and escaped variables.  */
 
 static void
-handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> rhsc,
+handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> &rhsc,
 		 tree fndecl)
 {
   auto_vec<ce_s> lhsc;
@@ -4609,9 +4609,10 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
       case BUILT_IN_REALLOC:
 	if (gimple_call_lhs (t))
 	  {
+	    auto_vec<ce_s> rhsc;
 	    handle_lhs_call (t, gimple_call_lhs (t),
 			     gimple_call_return_flags (t) | ERF_NOALIAS,
-			     vNULL, fndecl);
+			     rhsc, fndecl);
 	    get_constraint_for_ptr_offset (gimple_call_lhs (t),
 					   NULL_TREE, &lhsc);
 	    get_constraint_for_ptr_offset (gimple_call_arg (t, 0),
@@ -5682,7 +5683,7 @@ fieldoff_compare (const void *pa, const void *pb)
 
 /* Sort a fieldstack according to the field offset and sizes.  */
 static void
-sort_fieldstack (vec<fieldoff_s> fieldstack)
+sort_fieldstack (vec<fieldoff_s> &fieldstack)
 {
   fieldstack.qsort (fieldoff_compare);
 }
@@ -6092,7 +6093,7 @@ create_function_info_for (tree decl, const char *name, bool add_id,
    FIELDSTACK is assumed to be sorted by offset.  */
 
 static bool
-check_for_overlaps (vec<fieldoff_s> fieldstack)
+check_for_overlaps (const vec<fieldoff_s> &fieldstack)
 {
   fieldoff_s *fo = NULL;
   unsigned int i;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 579149dfd61..1e929fa002c 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -208,7 +208,7 @@ vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 static void
 vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
 {
-  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
+  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < checks.length(); ++i)
     if (checks[i] == value)
       return;
@@ -2346,7 +2346,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   if (do_versioning)
     {
       vec<stmt_vec_info> may_misalign_stmts
-        = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
+	= LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo).to_vec ();
       stmt_vec_info stmt_info;
 
       /* It can now be assumed that the data references in the statements
@@ -3360,7 +3360,8 @@ static void
 vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
 			poly_uint64 min_value)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  vec<vec_lower_bound> lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     if (operand_equal_p (lower_bounds[i].expr, expr, 0))
       {
@@ -3462,7 +3463,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
   hash_set <tree_pair_hash> compared_objects;
 
-  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
+  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).to_vec ();
   vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
     = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
   vec<vec_object_pair> &check_unequal_addrs
@@ -5335,7 +5336,7 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
    I4:  6 14 22 30  7 15 23 31.  */
 
 void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> dr_chain,
+vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
 			  unsigned int length,
 			  stmt_vec_info stmt_info,
 			  gimple_stmt_iterator *gsi,
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index 012f48bd487..9ff48fec729 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -3168,7 +3168,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
                                    tree *cond_expr,
 				   gimple_seq *cond_expr_stmt_list)
 {
-  vec<stmt_vec_info> may_misalign_stmts
+  const vec<stmt_vec_info> &may_misalign_stmts
     = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
   stmt_vec_info stmt_info;
   int mask = LOOP_VINFO_PTR_MASK (loop_vinfo);
@@ -3259,7 +3259,8 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
 static void
 vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_object_pair> pairs = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
+  const vec<vec_object_pair> &pairs
+    = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
   unsigned int i;
   vec_object_pair *pair;
   FOR_EACH_VEC_ELT (pairs, i, pair)
@@ -3278,7 +3279,8 @@ vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 static void
 vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  const vec<vec_lower_bound> &lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     {
       tree expr = lower_bounds[i].expr;
@@ -3320,7 +3322,7 @@ vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 void
 vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
 {
-  vec<dr_with_seg_len_pair_t> comp_alias_ddrs =
+  const vec<dr_with_seg_len_pair_t> &comp_alias_ddrs =
     LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
 
   if (comp_alias_ddrs.is_empty ())
diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c
index d536494a1bd..571b29322c5 100644
--- a/gcc/tree-vect-slp-patterns.c
+++ b/gcc/tree-vect-slp-patterns.c
@@ -746,7 +746,7 @@ vect_match_call_complex_mla (slp_tree node, unsigned child,
    of the negate node.  */
 
 static inline bool
-vect_normalize_conj_loc (vec<slp_tree> args, bool *neg_first_p = NULL)
+vect_normalize_conj_loc (vec<slp_tree> &args, bool *neg_first_p = NULL)
 {
   gcc_assert (args.length () == 2);
   bool neg_found = false;
@@ -790,7 +790,8 @@ is_eq_or_top (complex_perm_kinds_t perm, complex_perm_kinds_t kind)
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> left_op, vec<slp_tree> right_op,
+			      const vec<slp_tree> &left_op,
+			      const vec<slp_tree> &right_op,
 			     bool neg_first, bool *conj_first_operand,
 			     bool fms)
 {
@@ -862,7 +863,8 @@ vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> op, complex_perm_kinds_t permKind)
+			      const vec<slp_tree> &op,
+			      complex_perm_kinds_t permKind)
 {
   /* The left node is the more common case, test it first.  */
   if (!is_eq_or_top (linear_loads_p (perm_cache, op[0]), permKind))
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 227d6aa3ee8..9aee024cbf7 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -3316,7 +3316,8 @@ vect_analyze_slp_instance (vec_info *vinfo,
   else if (kind == slp_inst_kind_reduc_group)
     {
       /* Collect reduction statements.  */
-      vec<stmt_vec_info> reductions = as_a <loop_vec_info> (vinfo)->reductions;
+      const vec<stmt_vec_info> &reductions
+	= as_a <loop_vec_info> (vinfo)->reductions;
       scalar_stmts.create (reductions.length ());
       for (i = 0; reductions.iterate (i, &next_info); i++)
 	if (STMT_VINFO_RELEVANT_P (next_info)
@@ -4047,7 +4048,8 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
 {
   unsigned int i;
   poly_uint64 unrolling_factor = 1;
-  vec<slp_instance> slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
+  const vec<slp_instance> &slp_instances
+    = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
   slp_instance instance;
   int decided_to_slp = 0;
 
@@ -5814,7 +5816,7 @@ vect_slp_region (vec<basic_block> bbs, vec<data_reference_p> datarefs,
    true if anything in the basic-block was vectorized.  */
 
 static bool
-vect_slp_bbs (vec<basic_block> bbs)
+vect_slp_bbs (const vec<basic_block> &bbs)
 {
   vec<data_reference_p> datarefs = vNULL;
   auto_vec<int> dataref_groups;
@@ -5959,7 +5961,7 @@ vect_slp_function (function *fun)
 
 void
 duplicate_and_interleave (vec_info *vinfo, gimple_seq *seq, tree vector_type,
-			  vec<tree> elts, unsigned int nresults,
+			  vec<tree> &elts, unsigned int nresults,
 			  vec<tree> &results)
 {
   unsigned int nelts = elts.length ();
@@ -6315,7 +6317,7 @@ vect_get_slp_defs (vec_info *,
 
 bool
 vect_transform_slp_perm_load (vec_info *vinfo,
-			      slp_tree node, vec<tree> dr_chain,
+			      slp_tree node, const vec<tree> &dr_chain,
 			      gimple_stmt_iterator *gsi, poly_uint64 vf,
 			      bool analyze_only, unsigned *n_perms,
 			      unsigned int *n_loads, bool dce_chain)
@@ -7329,7 +7331,7 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance,
 /* Generate vector code for SLP_INSTANCES in the loop/basic block.  */
 
 void
-vect_schedule_slp (vec_info *vinfo, vec<slp_instance> slp_instances)
+vect_schedule_slp (vec_info *vinfo, const vec<slp_instance> &slp_instances)
 {
   slp_instance instance;
   unsigned int i;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 4ee11b2041a..7d99199b968 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4437,7 +4437,7 @@ static void
 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
 				       int multi_step_cvt,
 				       stmt_vec_info stmt_info,
-				       vec<tree> vec_dsts,
+				       vec<tree> &vec_dsts,
 				       gimple_stmt_iterator *gsi,
 				       slp_tree slp_node, enum tree_code code)
 {
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index fa28336d429..688bdaffcb5 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1927,8 +1927,8 @@ extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT);
 extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
 extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
 extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
-extern void vect_permute_store_chain (vec_info *,
-				      vec<tree> ,unsigned int, stmt_vec_info,
+extern void vect_permute_store_chain (vec_info *, vec<tree> &,
+				      unsigned int, stmt_vec_info,
 				      gimple_stmt_iterator *, vec<tree> *);
 extern tree vect_setup_realignment (vec_info *,
 				    stmt_vec_info, gimple_stmt_iterator *,
@@ -2009,12 +2009,12 @@ extern tree cse_and_gimplify_to_preheader (loop_vec_info, tree);
 extern void vect_slp_init (void);
 extern void vect_slp_fini (void);
 extern void vect_free_slp_instance (slp_instance);
-extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, vec<tree>,
+extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, const vec<tree> &,
 					  gimple_stmt_iterator *, poly_uint64,
 					  bool, unsigned *,
 					  unsigned * = nullptr, bool = false);
 extern bool vect_slp_analyze_operations (vec_info *);
-extern void vect_schedule_slp (vec_info *, vec<slp_instance>);
+extern void vect_schedule_slp (vec_info *, const vec<slp_instance> &);
 extern opt_result vect_analyze_slp (vec_info *, unsigned);
 extern bool vect_make_slp_decision (loop_vec_info);
 extern void vect_detect_hybrid_slp (loop_vec_info);
@@ -2032,7 +2032,7 @@ extern bool can_duplicate_and_interleave_p (vec_info *, unsigned int, tree,
 					    unsigned int * = NULL,
 					    tree * = NULL, tree * = NULL);
 extern void duplicate_and_interleave (vec_info *, gimple_seq *, tree,
-				      vec<tree>, unsigned int, vec<tree> &);
+				      vec<tree> &, unsigned int, vec<tree> &);
 extern int vect_get_place_in_interleaving_chain (stmt_vec_info, stmt_vec_info);
 extern bool vect_update_shared_vectype (stmt_vec_info, tree);
 extern slp_tree vect_create_new_slp_node (unsigned, tree_code);
diff --git a/gcc/tree.c b/gcc/tree.c
index 1aa6e557a04..bead1ac134c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2047,7 +2047,7 @@ make_vector (unsigned log2_npatterns,
    are extracted from V, a vector of CONSTRUCTOR_ELT.  */
 
 tree
-build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
+build_vector_from_ctor (tree type, const vec<constructor_elt, va_gc> *v)
 {
   if (vec_safe_length (v) == 0)
     return build_zero_cst (type);
@@ -14428,7 +14428,7 @@ test_labels ()
    are given by VALS.  */
 
 static tree
-build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
+build_vector (tree type, const vec<tree> &vals MEM_STAT_DECL)
 {
   gcc_assert (known_eq (vals.length (), TYPE_VECTOR_SUBPARTS (type)));
   tree_vector_builder builder (type, vals.length (), 1);
@@ -14439,7 +14439,7 @@ build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
 /* Check that VECTOR_CST ACTUAL contains the elements in EXPECTED.  */
 
 static void
-check_vector_cst (vec<tree> expected, tree actual)
+check_vector_cst (const vec<tree> &expected, tree actual)
 {
   ASSERT_KNOWN_EQ (expected.length (),
 		   TYPE_VECTOR_SUBPARTS (TREE_TYPE (actual)));
@@ -14452,7 +14452,7 @@ check_vector_cst (vec<tree> expected, tree actual)
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_duplicate (vec<tree> expected, tree actual,
+check_vector_cst_duplicate (const vec<tree> &expected, tree actual,
 			    unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14468,7 +14468,7 @@ check_vector_cst_duplicate (vec<tree> expected, tree actual,
    EXPECTED.  */
 
 static void
-check_vector_cst_fill (vec<tree> expected, tree actual,
+check_vector_cst_fill (const vec<tree> &expected, tree actual,
 		       unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14483,7 +14483,7 @@ check_vector_cst_fill (vec<tree> expected, tree actual,
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_stepped (vec<tree> expected, tree actual,
+check_vector_cst_stepped (const vec<tree> &expected, tree actual,
 			  unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
diff --git a/gcc/tree.h b/gcc/tree.h
index 060ddee09dd..7043ae2cddc 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4474,7 +4474,7 @@ extern tree build_int_cst (tree, poly_int64);
 extern tree build_int_cstu (tree type, poly_uint64);
 extern tree build_int_cst_type (tree, poly_int64);
 extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO);
-extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
+extern tree build_vector_from_ctor (tree, const vec<constructor_elt, va_gc> *);
 extern tree build_vector_from_val (tree, tree);
 extern tree build_uniform_cst (tree, tree);
 extern tree build_vec_series (tree, tree, tree);
diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..6d767cc12c1 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -38,16 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #endif
 
-/* vNULL is an empty type with a template cast operation that returns
-   a zero-initialized vec<T, A, L> instance.  Use this when you want
-   to assign nil values to new vec instances or pass a nil vector as
-   a function call argument.
-
-   We use this technique because vec<T, A, L> must be PODs (they are
-   stored in unions and passed in vararg functions), this means that
-   they cannot have ctors/dtors.  */
-vnull vNULL;
-
 /* Vector memory usage.  */
 class vec_usage: public mem_usage
 {
@@ -282,6 +272,42 @@ safe_push_range (vec <int>&v, int start, int limit)
     v.safe_push (i);
 }
 
+/* Verify forms of initialization.  */
+
+static void
+test_init ()
+{
+  {
+    vec<int> v1{ };
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 = vec<int>();
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 = v1;
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 (vNULL);
+    ASSERT_EQ (0, v1.length ());
+    v1.safe_push (1);
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (1, v1.length ());
+    v2.safe_push (1);
+
+    ASSERT_EQ (2, v1.length ());
+    ASSERT_EQ (2, v2.length ());
+    v1.release ();
+  }
+}
+
 /* Verify that vec::quick_push works correctly.  */
 
 static void
@@ -547,6 +573,7 @@ test_auto_delete_vec ()
 void
 vec_c_tests ()
 {
+  test_init ();
   test_quick_push ();
   test_safe_push ();
   test_truncate ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..fef3dda6a38 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -541,18 +541,16 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
     ::new (static_cast<void*>(dst)) T (*src);
 }
 
-/* Type to provide NULL values for vec<T, A, L>.  This is used to
-   provide nil initializers for vec instances.  Since vec must be
-   a POD, we cannot have proper ctor/dtor for it.  To initialize
-   a vec instance, you can assign it the value vNULL.  This isn't
-   needed for file-scope and function-local static vectors, which
-   are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
-extern vnull vNULL;
+/* Type to provide zero-initialized values for vec<T, A, L>.  This is
+   used to  provide nil initializers for vec instances.  Since vec must
+   be a trivially copyable type that can be copied by memcpy and zeroed
+   out by memset, it must have defaulted default and copy ctor and copy
+   assignment.  To initialize a vec either use value initialization
+   (e.g., vec() or vec v{ };) or assign it the value vNULL.  This isn't
+   needed for file-scope and function-local static vectors, which are
+   zero-initialized by default.  */
+struct vnull { };
+static constexpr vnull vNULL{ };
 
 
 /* Embeddable vector.  These vectors are suitable to be embedded
@@ -1431,10 +1429,34 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
    As long as we use C++03, we cannot have constructors nor
    destructors in classes that are stored in unions.  */
 
+template<typename T, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  /* Default ctors to ensure triviality.  Use value-initialization
+     (e.g., vec() or vec v{ };) or vNULL to create a zero-initialized
+     instance.  */
+  vec () = default;
+  vec (const vec &) = default;
+  /* Initialization from the generic vNULL.  */
+  vec (vnull): m_vec () { }
+  /* Same as default ctor: vec storage must be released manually.  */
+  ~vec () = default;
+
+  /* Defaulted same as copy ctor.  */
+  vec& operator= (const vec &) = default;
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1544,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1571,13 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1631,13 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // 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 ().
@@ -1781,7 +1817,7 @@ template<typename T>
 inline vec<T, va_heap, vl_ptr>
 vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
 {
-  vec<T, va_heap, vl_ptr> new_vec = vNULL;
+  vec<T, va_heap, vl_ptr> new_vec{ };
   if (length ())
     new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT);
   return new_vec;

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-29 17:18                           ` Martin Sebor
@ 2021-06-30  8:40                             ` Richard Biener
  2021-06-30  9:00                               ` Richard Sandiford
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-06-30  8:40 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Tue, Jun 29, 2021 at 7:18 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/29/21 8:43 AM, Jason Merrill wrote:
> > On 6/28/21 2:07 PM, Martin Sebor wrote:
> >> On 6/28/21 2:07 AM, Richard Biener wrote:
> >>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
> >>>>
> >>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
> >>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
> >>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
> >>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
> >>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
> >>>>>>>>>>> wrote:
> >>>>>>>>>>>>
> >>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign
> >>>>>>>>>>>>>> because
> >>>>>>>>>>>>>> the class manages its own memory but doesn't define (or
> >>>>>>>>>>>>>> delete)
> >>>>>>>>>>>>>> either special function.  Since I first ran into the problem,
> >>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>>>>>>>> assignment operator.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
> >>>>>>>>>>>>>> along
> >>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>>>>>>>> containers
> >>>>>>>>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>>>>>>>> bootstrap
> >>>>>>>>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The question is whether we want such uses to appear since
> >>>>>>>>>>>>> those
> >>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>>>>>>>> operators?
> >>>>>>>>>>>>
> >>>>>>>>>>>> I would strongly prefer the generic vector class to have the
> >>>>>>>>>>>> properties
> >>>>>>>>>>>> expected of any other generic container: copyable and
> >>>>>>>>>>>> assignable.  If
> >>>>>>>>>>>> we also want another vector type with this restriction I
> >>>>>>>>>>>> suggest
> >>>>>>>>>>>> to add
> >>>>>>>>>>>> another "noncopyable" type and make that property explicit in
> >>>>>>>>>>>> its name.
> >>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>>>>>>>
> >>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>>>>>>>> Looking around
> >>>>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<>
> >>>>>>>>>>> do it
> >>>>>>>>>>> might be surprising (I added the move capability to match how
> >>>>>>>>>>> vec<>
> >>>>>>>>>>> is used - as "reference" to a vector)
> >>>>>>>>>>
> >>>>>>>>>> The vec base classes are special: they have no ctors at all
> >>>>>>>>>> (because
> >>>>>>>>>> of their use in unions).  That's something we might have to
> >>>>>>>>>> live with
> >>>>>>>>>> but it's not a model to follow in ordinary containers.
> >>>>>>>>>
> >>>>>>>>> I don't think we have to live with it anymore, now that we're
> >>>>>>>>> writing C++11.
> >>>>>>>>>
> >>>>>>>>>> The auto_vec class was introduced to fill the need for a
> >>>>>>>>>> conventional
> >>>>>>>>>> sequence container with a ctor and dtor.  The missing copy
> >>>>>>>>>> ctor and
> >>>>>>>>>> assignment operators were an oversight, not a deliberate feature.
> >>>>>>>>>> This change fixes that oversight.
> >>>>>>>>>>
> >>>>>>>>>> The revised patch also adds a copy ctor/assignment to the
> >>>>>>>>>> auto_vec
> >>>>>>>>>> primary template (that's also missing it).  In addition, it adds
> >>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
> >>>>>>>>>> assignment as you prefer.
> >>>>>>>>>
> >>>>>>>>> Hmm, adding another class doesn't really help with the confusion
> >>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>>>>>>>> which will still do a shallow copy.  I think it's probably better
> >>>>>>>>> to disable the copy special members for auto_vec until we fix
> >>>>>>>>> vec<>.
> >>>>>>>>
> >>>>>>>> There are at least a couple of problems that get in the way of
> >>>>>>>> fixing
> >>>>>>>> all of vec to act like a well-behaved C++ container:
> >>>>>>>>
> >>>>>>>> 1) The embedded vec has a trailing "flexible" array member with its
> >>>>>>>> instances having different size.  They're initialized by memset and
> >>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
> >>>>>>>> but it should disable/delete them instead.
> >>>>>>>>
> >>>>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
> >>>>>>>> shallow copy semantics (not just as function arguments but also as
> >>>>>>>> members of other such POD classes).  This can be changed by
> >>>>>>>> providing
> >>>>>>>> copy and move ctors and assignment operators for it, and also for
> >>>>>>>> some of the classes in which it's a member and that are used with
> >>>>>>>> the same assumption.
> >>>>>>>>
> >>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are
> >>>>>>>> PODs.
> >>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >>>>>>>> and tree-vect-patterns.c).
> >>>>>>>>
> >>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
> >>>>>>>> be a big and tricky project.  Tricky because it involves using
> >>>>>>>> std::move in places where what's moved is subsequently still used.
> >>>>>>>> I can keep plugging away at it but it won't change the fact that
> >>>>>>>> the embedded and heap-based vecs have different requirements.
> >>>>>>>>
> >>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
> >>>>>>>> to be put on hold until the rats nest above is untangled.  It won't
> >>>>>>>> make anything worse than it is.  (I have a project that depends on
> >>>>>>>> a sane auto_vec working).
> >>>>>>>>
> >>>>>>>> A couple of alternatives to solving this are to use std::vector or
> >>>>>>>> write an equivalent vector class just for GCC.
> >>>>>>>
> >>>>>>> It occurs to me that another way to work around the issue of passing
> >>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
> >>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This
> >>>>>>> would
> >>>>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
> >>>>>>> be by reference.  We might as well do the same for operator=, though
> >>>>>>> that isn't as important.
> >>>>>>
> >>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
> >>>>>> of this change.  Since the auto_vec copy ctor and assignment have
> >>>>>> been deleted by someone else in the interim, this patch doesn't
> >>>>>> reverse that.  I will propose it separately after these changes
> >>>>>> are finalized.
> >>>>>>
> >>>>>> My approach was to 1) disable the auto_vec to vec conversion,
> >>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
> >>>>>> explicitly, and 3) resolve compilation errors by either changing
> >>>>>> APIs to take a vec by reference or callers to convert auto_vec to
> >>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> >>>>>> improving the const-correctness of the APIs.
> >>>>>
> >>>>> What did you base the choice between reference or to_vec on?  For
> >>>>> instance, it seems like c_parser_declaration_or_fndef could use a
> >>>>> reference, but you changed the callers instead.
> >>>>
> >>>> I went with a reference whenever I could.  That doesn't work when
> >>>> there are callers that pass in a vNULL, so there, and in assignments,
> >>>> I used to_vec().
> >>>
> >>> Is there a way to "fix" the ugliness with vNULL?  All those functions
> >>> should be able to use const vec<>& as otherwise they'd leak memory?
> >>> Can't we pass vNULL to a const vec<>&?
> >>
> >> vNULL can bind to a const vec& (via the vec conversion ctor) but
> >> not to vec&.  The three functions that in the patch are passed
> >> vNULL modify the argument when it's not vNULL but not otherwise.
> >
> > The c_parser_declaration_or_fndef case is rather ugly: the vec is passed
> > by value, but then the modifications in c_finish_omp_declare_simd modify
> > the original vec.
> >
> > We could keep the same semantic problem and make it more blatant by
> > changing to const vec& and doing a const_cast in
> > c_finish_omp_declare_simd before modifying the vec.
> >
> > Do the other two have the same problem?
>
> Yes, the functions that take a vec by value and are passed an auto_vec
> "by reference" (the result of to_vec()) modify the auto_vec.  This is
> the "bug" this patch is designed to keep from happening by accident,
> while letting the API clients do it intentionally.
>
> Changing these APIs to take a const vec& while still letting them
> modify the argument by casting away the constness seems even more
> surprising to me than the current by-value style.
>
> I do think it should be fixed but I'd have been more comfortable
> handling that separately.  Attached is a (near) minimal change
> along these lines to c_parser_declaration_or_fndef and its callers.
> The logic isn't exactly the same as the original but no tests fail.
> If this is the direction we want to go in I can see about making
> an analogous change to the other two similar functions in the patch.
> Let me know.

Note there's also array_slice<> which could be used to pass non-const
vec<>s that are never resized but modified - the only "valid" case of
passing a non-const vec<> by value.  But as noted array_slice<> lacks
most of the vec<> API so I'm not sure how awkward that option would be.
We of course can amend its API as well.

Richard.

> Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-30  1:46                           ` Martin Sebor
@ 2021-06-30  8:48                             ` Richard Biener
  2021-06-30  9:29                               ` Martin Jambor
  2021-07-06 15:06                             ` [PING][PATCH] " Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-06-30  8:48 UTC (permalink / raw)
  To: Martin Sebor, Martin Jambor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Wed, Jun 30, 2021 at 3:46 AM Martin Sebor <msebor@gmail.com> wrote:
>
> On 6/29/21 4:58 AM, Richard Biener wrote:
> > On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
> >>
> >> On 6/28/21 2:07 AM, Richard Biener wrote:
> >>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
> >>>>
> >>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
> >>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
> >>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
> >>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
> >>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
> >>>>>>>>>>> wrote:
> >>>>>>>>>>>>
> >>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign because
> >>>>>>>>>>>>>> the class manages its own memory but doesn't define (or delete)
> >>>>>>>>>>>>>> either special function.  Since I first ran into the problem,
> >>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>>>>>>>> assignment operator.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> The attached patch adds the two special functions to auto_vec
> >>>>>>>>>>>>>> along
> >>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>>>>>>>> containers
> >>>>>>>>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>>>>>>>> bootstrap
> >>>>>>>>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The question is whether we want such uses to appear since those
> >>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>>>>>>>> operators?
> >>>>>>>>>>>>
> >>>>>>>>>>>> I would strongly prefer the generic vector class to have the
> >>>>>>>>>>>> properties
> >>>>>>>>>>>> expected of any other generic container: copyable and
> >>>>>>>>>>>> assignable.  If
> >>>>>>>>>>>> we also want another vector type with this restriction I suggest
> >>>>>>>>>>>> to add
> >>>>>>>>>>>> another "noncopyable" type and make that property explicit in
> >>>>>>>>>>>> its name.
> >>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>>>>>>>
> >>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>>>>>>>> Looking around
> >>>>>>>>>>> I see that vec<> does not do deep copying.  Making auto_vec<> do it
> >>>>>>>>>>> might be surprising (I added the move capability to match how vec<>
> >>>>>>>>>>> is used - as "reference" to a vector)
> >>>>>>>>>>
> >>>>>>>>>> The vec base classes are special: they have no ctors at all (because
> >>>>>>>>>> of their use in unions).  That's something we might have to live with
> >>>>>>>>>> but it's not a model to follow in ordinary containers.
> >>>>>>>>>
> >>>>>>>>> I don't think we have to live with it anymore, now that we're
> >>>>>>>>> writing C++11.
> >>>>>>>>>
> >>>>>>>>>> The auto_vec class was introduced to fill the need for a conventional
> >>>>>>>>>> sequence container with a ctor and dtor.  The missing copy ctor and
> >>>>>>>>>> assignment operators were an oversight, not a deliberate feature.
> >>>>>>>>>> This change fixes that oversight.
> >>>>>>>>>>
> >>>>>>>>>> The revised patch also adds a copy ctor/assignment to the auto_vec
> >>>>>>>>>> primary template (that's also missing it).  In addition, it adds
> >>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
> >>>>>>>>>> assignment as you prefer.
> >>>>>>>>>
> >>>>>>>>> Hmm, adding another class doesn't really help with the confusion
> >>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>>>>>>>> which will still do a shallow copy.  I think it's probably better
> >>>>>>>>> to disable the copy special members for auto_vec until we fix vec<>.
> >>>>>>>>
> >>>>>>>> There are at least a couple of problems that get in the way of fixing
> >>>>>>>> all of vec to act like a well-behaved C++ container:
> >>>>>>>>
> >>>>>>>> 1) The embedded vec has a trailing "flexible" array member with its
> >>>>>>>> instances having different size.  They're initialized by memset and
> >>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
> >>>>>>>> but it should disable/delete them instead.
> >>>>>>>>
> >>>>>>>> 2) The heap-based vec is used throughout GCC with the assumption of
> >>>>>>>> shallow copy semantics (not just as function arguments but also as
> >>>>>>>> members of other such POD classes).  This can be changed by providing
> >>>>>>>> copy and move ctors and assignment operators for it, and also for
> >>>>>>>> some of the classes in which it's a member and that are used with
> >>>>>>>> the same assumption.
> >>>>>>>>
> >>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are PODs.
> >>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >>>>>>>> and tree-vect-patterns.c).
> >>>>>>>>
> >>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
> >>>>>>>> be a big and tricky project.  Tricky because it involves using
> >>>>>>>> std::move in places where what's moved is subsequently still used.
> >>>>>>>> I can keep plugging away at it but it won't change the fact that
> >>>>>>>> the embedded and heap-based vecs have different requirements.
> >>>>>>>>
> >>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
> >>>>>>>> to be put on hold until the rats nest above is untangled.  It won't
> >>>>>>>> make anything worse than it is.  (I have a project that depends on
> >>>>>>>> a sane auto_vec working).
> >>>>>>>>
> >>>>>>>> A couple of alternatives to solving this are to use std::vector or
> >>>>>>>> write an equivalent vector class just for GCC.
> >>>>>>>
> >>>>>>> It occurs to me that another way to work around the issue of passing
> >>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
> >>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This would
> >>>>>>> mean if you want to pass an auto_vec to a vec interface, it needs to
> >>>>>>> be by reference.  We might as well do the same for operator=, though
> >>>>>>> that isn't as important.
> >>>>>>
> >>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
> >>>>>> of this change.  Since the auto_vec copy ctor and assignment have
> >>>>>> been deleted by someone else in the interim, this patch doesn't
> >>>>>> reverse that.  I will propose it separately after these changes
> >>>>>> are finalized.
> >>>>>>
> >>>>>> My approach was to 1) disable the auto_vec to vec conversion,
> >>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
> >>>>>> explicitly, and 3) resolve compilation errors by either changing
> >>>>>> APIs to take a vec by reference or callers to convert auto_vec to
> >>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> >>>>>> improving the const-correctness of the APIs.
> >>>>>
> >>>>> What did you base the choice between reference or to_vec on?  For
> >>>>> instance, it seems like c_parser_declaration_or_fndef could use a
> >>>>> reference, but you changed the callers instead.
> >>>>
> >>>> I went with a reference whenever I could.  That doesn't work when
> >>>> there are callers that pass in a vNULL, so there, and in assignments,
> >>>> I used to_vec().
> >>>
> >>> Is there a way to "fix" the ugliness with vNULL?  All those functions
> >>> should be able to use const vec<>& as otherwise they'd leak memory?
> >>> Can't we pass vNULL to a const vec<>&?
> >>
> >> vNULL can bind to a const vec& (via the vec conversion ctor) but
> >> not to vec&.  The three functions that in the patch are passed
> >> vNULL modify the argument when it's not vNULL but not otherwise.
> >> An alternate design is to have them take a vec* and pass in
> >> a plain NULL (or nullptr) instead of vNULL.  That would require
> >> some surgery on the function bodies that I've been trying to
> >> avoid in the first pass.
> >
> > But I wonder if since you now identified them they could be massaged
> > prior to doing the change.
> >
> > I do hope we end up not needing .to_vec () after all, if no users remain ;)
>
> I'd be happy to if none remained.  I see how to eliminate those in
> calls to functions like c_parser_declaration_or_fndef() (done in
> the attached revision of the patch), but no easy way to get rid
> of those that replace other implicit conversions, like all those
> assignments to the vec members of the ipa_call_arg_values ctor.
> If it's appropriate to std::move those then that would get rid
> of the .to_vec () call.  I'm not familiar with the code but I
> have the impression it might be meant more as a reference to
> some "remote" object (an instance of ipa_auto_call_arg_values?)
> If that's right then making the vec members auto_vec references
> (or pointers) would be one way to "fix" this.

I think ipa_call_arg_values is just a temporary container used to
pass a collection of vec<>s along API boundaries.  I'm not sure
whether it's default CTOR is ever used but it's definitely an
optimization avoiding extra indirection (when changing the vec<>
members to vec<> * or references, in case the default CTOR is
not used).  It _might_ be that the vecs are all just read and never
written to in the APIs using this abstract type but then it's
likely the vector are always appropriately pre-allocated.

Maybe using array_slice instead of vec<> members would work,
but they'd pack less efficient (but I guess not an issue for this
aggregate which should be only used temporarily for argument
passing).

I suppose Martin can answer most of the above ...

>
> >> Functions that don't leak memory now shouldn't leak with these
> >> changes, and conversely, those that do will still leak.  The patch
> >> doesn't change that (as far as I know).
> >
> > It just occurs to me those cases could pass auto_vec<>() by reference instead
> > of vNULL?  So if the vector is modified then it's released afterwards?
> > That would fix the memleak.
>
> I see what you mean.  A function that modified the unnamed vec
> temporary constructed from vNULL then the modified vector would
> leak.  I don't think the functions the patch touches do that but
> I've removed the vNULL conversion from all of them.  There are
> many others that pass vNULL to a vec arguments that that the patch
> doesn't touch but those would be worth a closer look at some point.

Yeah.

> Attached is a revised patch with these changes (a superset of
> those I sent in response to Jason's question), tested on x86_64.
>
> Martin
>
> >
> >> Going forward I think it's possible to replace most uses of vNULL
> >> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
> >> can't be readily replaced are the ones where vNULL is passed as
> >> an argument to functions taking a vec by value.  Those could be
> >> changed to avoid vNULL too, but it would take a different approach
> >> and more effort.  I'm not against it but I'd rather decouple those
> >> changes from this already sizeable patch.
> >>
> >> Martin
> >>
> >>>
> >>> Richard.
> >>>
> >>>>
> >>>> Martin
> >>>>
> >>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-30  8:40                             ` Richard Biener
@ 2021-06-30  9:00                               ` Richard Sandiford
  2021-06-30 12:01                                 ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Sandiford @ 2021-06-30  9:00 UTC (permalink / raw)
  To: Richard Biener via Gcc-patches
  Cc: Martin Sebor, Richard Biener, Jonathan Wakely

Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> Note there's also array_slice<> which could be used to pass non-const
> vec<>s that are never resized but modified - the only "valid" case of
> passing a non-const vec<> by value.

Yeah.  We'd need a new constructor for that (the current one only
takes const vec<>&) but I agree it would be a good thing to do.

I realise you weren't saying otherwise, but: array_slice<> can also be
used for const vec<>s.  E.g. array_slice<const int> can't be resized
or modified.

I think array_slice<> is going to be more efficient as well.  E.g.:

void
f1 (vec<char> &foo)
{
  for (unsigned int i = 0; i < foo.length (); ++i)
    foo[i] += 1;
}

void
f2 (array_slice<char> foo)
{
  for (unsigned int i = 0; i < foo.size (); ++i)
    foo[i] += 1;
}

gives:

000000000000d150 <f1(vec<char, va_heap, vl_ptr>&)>:
    d150:       48 8b 07                mov    (%rdi),%rax
    d153:       31 d2                   xor    %edx,%edx
    d155:       48 85 c0                test   %rax,%rax
    d158:       74 26                   je     d180 <f1(vec<char, va_heap, vl_ptr>&)+0x30>
    d15a:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
    d160:       3b 50 04                cmp    0x4(%rax),%edx
    d163:       73 12                   jae    d177 <f1(vec<char, va_heap, vl_ptr>&)+0x27>
    d165:       89 d1                   mov    %edx,%ecx
    d167:       83 c2 01                add    $0x1,%edx
    d16a:       80 44 08 08 01          addb   $0x1,0x8(%rax,%rcx,1)
    d16f:       48 8b 07                mov    (%rdi),%rax
    d172:       48 85 c0                test   %rax,%rax
    d175:       75 e9                   jne    d160 <f1(vec<char, va_heap, vl_ptr>&)+0x10>
    d177:       c3                      retq
    d178:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
    d17f:       00
    d180:       c3                      retq

000000000000d190 <f2(array_slice<char>)>:
    d190:       85 f6                   test   %esi,%esi
    d192:       74 18                   je     d1ac <f2(array_slice<char>)+0x1c>
    d194:       8d 46 ff                lea    -0x1(%rsi),%eax
    d197:       48 8d 44 07 01          lea    0x1(%rdi,%rax,1),%rax
    d19c:       0f 1f 40 00             nopl   0x0(%rax)
    d1a0:       80 07 01                addb   $0x1,(%rdi)
    d1a3:       48 83 c7 01             add    $0x1,%rdi
    d1a7:       48 39 c7                cmp    %rax,%rdi
    d1aa:       75 f4                   jne    d1a0 <f2(array_slice<char>)+0x10>
    d1ac:       c3                      retq

where f1 has to reload the length and base each iteration,
but f2 doesn't.

> But as noted array_slice<> lacks most of the vec<> API so I'm not sure
> how awkward that option would be.  We of course can amend its API as
> well.

Yeah, that'd be good.  The current class follows the principle
“don't add stuff that isn't needed yet”. :-)

Thanks,
Richard

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-30  8:48                             ` Richard Biener
@ 2021-06-30  9:29                               ` Martin Jambor
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Jambor @ 2021-06-30  9:29 UTC (permalink / raw)
  To: Richard Biener, Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

Hi,

On Wed, Jun 30 2021, Richard Biener wrote:
> On Wed, Jun 30, 2021 at 3:46 AM Martin Sebor <msebor@gmail.com> wrote:
>> On 6/29/21 4:58 AM, Richard Biener wrote:

[...]

>> >
>> > But I wonder if since you now identified them they could be massaged
>> > prior to doing the change.
>> >
>> > I do hope we end up not needing .to_vec () after all, if no users remain ;)
>>
>> I'd be happy to if none remained.  I see how to eliminate those in
>> calls to functions like c_parser_declaration_or_fndef() (done in
>> the attached revision of the patch), but no easy way to get rid
>> of those that replace other implicit conversions, like all those
>> assignments to the vec members of the ipa_call_arg_values ctor.
>> If it's appropriate to std::move those then that would get rid
>> of the .to_vec () call.  I'm not familiar with the code but I
>> have the impression it might be meant more as a reference to
>> some "remote" object (an instance of ipa_auto_call_arg_values?)
>> If that's right then making the vec members auto_vec references
>> (or pointers) would be one way to "fix" this.
>
> I think ipa_call_arg_values is just a temporary container used to
> pass a collection of vec<>s along API boundaries.  I'm not sure
> whether it's default CTOR is ever used but it's definitely an
> optimization avoiding extra indirection (when changing the vec<>
> members to vec<> * or references, in case the default CTOR is
> not used).  It _might_ be that the vecs are all just read and never
> written to in the APIs using this abstract type

No, IPA-CP does add and then remove extra context-specific values in the
auto version of the container, ipa_auto_call_arg_values, but I do not
think that consumers of ipa_call_arg_values do.  The caching mechanism
can make a (partial) copy.

> but then it's
> likely the vector are always appropriately pre-allocated.

They are, they should never be reallocated.

> Maybe using array_slice instead of vec<> members would work,
> but they'd pack less efficient (but I guess not an issue for this
> aggregate which should be only used temporarily for argument
> passing).

I need to educate myself more about array_slice to to comment on that.
But note that apart from reducing the number of parameters, there is
also an ipa_call_arg_values field in ipa_call_context and especially
ipa_cached_call_context.

Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-30  9:00                               ` Richard Sandiford
@ 2021-06-30 12:01                                 ` Richard Biener
  0 siblings, 0 replies; 59+ messages in thread
From: Richard Biener @ 2021-06-30 12:01 UTC (permalink / raw)
  To: Richard Biener via Gcc-patches, Martin Sebor, Richard Biener,
	Jonathan Wakely, Richard Sandiford

On Wed, Jun 30, 2021 at 11:00 AM Richard Sandiford
<richard.sandiford@arm.com> wrote:
>
> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> > Note there's also array_slice<> which could be used to pass non-const
> > vec<>s that are never resized but modified - the only "valid" case of
> > passing a non-const vec<> by value.
>
> Yeah.  We'd need a new constructor for that (the current one only
> takes const vec<>&) but I agree it would be a good thing to do.
>
> I realise you weren't saying otherwise, but: array_slice<> can also be
> used for const vec<>s.  E.g. array_slice<const int> can't be resized
> or modified.
>
> I think array_slice<> is going to be more efficient as well.  E.g.:
>
> void
> f1 (vec<char> &foo)
> {
>   for (unsigned int i = 0; i < foo.length (); ++i)
>     foo[i] += 1;
> }
>
> void
> f2 (array_slice<char> foo)
> {
>   for (unsigned int i = 0; i < foo.size (); ++i)
>     foo[i] += 1;
> }
>
> gives:
>
> 000000000000d150 <f1(vec<char, va_heap, vl_ptr>&)>:
>     d150:       48 8b 07                mov    (%rdi),%rax
>     d153:       31 d2                   xor    %edx,%edx
>     d155:       48 85 c0                test   %rax,%rax
>     d158:       74 26                   je     d180 <f1(vec<char, va_heap, vl_ptr>&)+0x30>
>     d15a:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
>     d160:       3b 50 04                cmp    0x4(%rax),%edx
>     d163:       73 12                   jae    d177 <f1(vec<char, va_heap, vl_ptr>&)+0x27>
>     d165:       89 d1                   mov    %edx,%ecx
>     d167:       83 c2 01                add    $0x1,%edx
>     d16a:       80 44 08 08 01          addb   $0x1,0x8(%rax,%rcx,1)
>     d16f:       48 8b 07                mov    (%rdi),%rax
>     d172:       48 85 c0                test   %rax,%rax
>     d175:       75 e9                   jne    d160 <f1(vec<char, va_heap, vl_ptr>&)+0x10>
>     d177:       c3                      retq
>     d178:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
>     d17f:       00
>     d180:       c3                      retq
>
> 000000000000d190 <f2(array_slice<char>)>:
>     d190:       85 f6                   test   %esi,%esi
>     d192:       74 18                   je     d1ac <f2(array_slice<char>)+0x1c>
>     d194:       8d 46 ff                lea    -0x1(%rsi),%eax
>     d197:       48 8d 44 07 01          lea    0x1(%rdi,%rax,1),%rax
>     d19c:       0f 1f 40 00             nopl   0x0(%rax)
>     d1a0:       80 07 01                addb   $0x1,(%rdi)
>     d1a3:       48 83 c7 01             add    $0x1,%rdi
>     d1a7:       48 39 c7                cmp    %rax,%rdi
>     d1aa:       75 f4                   jne    d1a0 <f2(array_slice<char>)+0x10>
>     d1ac:       c3                      retq
>
> where f1 has to reload the length and base each iteration,
> but f2 doesn't.

Of course but that's unfair - by refrence vec<> vs. by value array_slice<>
plus char * pointer stores which destroy all TBAA ... ;)

>
> > But as noted array_slice<> lacks most of the vec<> API so I'm not sure
> > how awkward that option would be.  We of course can amend its API as
> > well.
>
> Yeah, that'd be good.  The current class follows the principle
> “don't add stuff that isn't needed yet”. :-)

Yes, and that's good of course.

Richard.

> Thanks,
> Richard

^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-06-30  1:46                           ` Martin Sebor
  2021-06-30  8:48                             ` Richard Biener
@ 2021-07-06 15:06                             ` Martin Sebor
  2021-07-07  7:28                               ` Richard Biener
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-07-06 15:06 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-June/573968.html

Any questions/suggestions on the final patch or is it okay to commit?

On 6/29/21 7:46 PM, Martin Sebor wrote:
> On 6/29/21 4:58 AM, Richard Biener wrote:
>> On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
>>>
>>> On 6/28/21 2:07 AM, Richard Biener wrote:
>>>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>>>>>
>>>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
>>>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
>>>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign 
>>>>>>>>>>>>>>> because
>>>>>>>>>>>>>>> the class manages its own memory but doesn't define (or 
>>>>>>>>>>>>>>> delete)
>>>>>>>>>>>>>>> either special function.  Since I first ran into the 
>>>>>>>>>>>>>>> problem,
>>>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>>>>>> assignment operator.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> The attached patch adds the two special functions to 
>>>>>>>>>>>>>>> auto_vec
>>>>>>>>>>>>>>> along
>>>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
>>>>>>>>>>>>>>> containers
>>>>>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>>>>>> bootstrap
>>>>>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The question is whether we want such uses to appear since 
>>>>>>>>>>>>>> those
>>>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>>>>>> operators?
>>>>>>>>>>>>>
>>>>>>>>>>>>> I would strongly prefer the generic vector class to have the
>>>>>>>>>>>>> properties
>>>>>>>>>>>>> expected of any other generic container: copyable and
>>>>>>>>>>>>> assignable.  If
>>>>>>>>>>>>> we also want another vector type with this restriction I 
>>>>>>>>>>>>> suggest
>>>>>>>>>>>>> to add
>>>>>>>>>>>>> another "noncopyable" type and make that property explicit in
>>>>>>>>>>>>> its name.
>>>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>>>>>
>>>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
>>>>>>>>>>>> Looking around
>>>>>>>>>>>> I see that vec<> does not do deep copying.  Making 
>>>>>>>>>>>> auto_vec<> do it
>>>>>>>>>>>> might be surprising (I added the move capability to match 
>>>>>>>>>>>> how vec<>
>>>>>>>>>>>> is used - as "reference" to a vector)
>>>>>>>>>>>
>>>>>>>>>>> The vec base classes are special: they have no ctors at all 
>>>>>>>>>>> (because
>>>>>>>>>>> of their use in unions).  That's something we might have to 
>>>>>>>>>>> live with
>>>>>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>>>>>
>>>>>>>>>> I don't think we have to live with it anymore, now that we're
>>>>>>>>>> writing C++11.
>>>>>>>>>>
>>>>>>>>>>> The auto_vec class was introduced to fill the need for a 
>>>>>>>>>>> conventional
>>>>>>>>>>> sequence container with a ctor and dtor.  The missing copy 
>>>>>>>>>>> ctor and
>>>>>>>>>>> assignment operators were an oversight, not a deliberate 
>>>>>>>>>>> feature.
>>>>>>>>>>> This change fixes that oversight.
>>>>>>>>>>>
>>>>>>>>>>> The revised patch also adds a copy ctor/assignment to the 
>>>>>>>>>>> auto_vec
>>>>>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>>>>>> assignment as you prefer.
>>>>>>>>>>
>>>>>>>>>> Hmm, adding another class doesn't really help with the confusion
>>>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
>>>>>>>>>> which will still do a shallow copy.  I think it's probably better
>>>>>>>>>> to disable the copy special members for auto_vec until we fix 
>>>>>>>>>> vec<>.
>>>>>>>>>
>>>>>>>>> There are at least a couple of problems that get in the way of 
>>>>>>>>> fixing
>>>>>>>>> all of vec to act like a well-behaved C++ container:
>>>>>>>>>
>>>>>>>>> 1) The embedded vec has a trailing "flexible" array member with 
>>>>>>>>> its
>>>>>>>>> instances having different size.  They're initialized by memset 
>>>>>>>>> and
>>>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>>>>>> but it should disable/delete them instead.
>>>>>>>>>
>>>>>>>>> 2) The heap-based vec is used throughout GCC with the 
>>>>>>>>> assumption of
>>>>>>>>> shallow copy semantics (not just as function arguments but also as
>>>>>>>>> members of other such POD classes).  This can be changed by 
>>>>>>>>> providing
>>>>>>>>> copy and move ctors and assignment operators for it, and also for
>>>>>>>>> some of the classes in which it's a member and that are used with
>>>>>>>>> the same assumption.
>>>>>>>>>
>>>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are 
>>>>>>>>> PODs.
>>>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>>>>>> and tree-vect-patterns.c).
>>>>>>>>>
>>>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>>>>>> be a big and tricky project.  Tricky because it involves using
>>>>>>>>> std::move in places where what's moved is subsequently still used.
>>>>>>>>> I can keep plugging away at it but it won't change the fact that
>>>>>>>>> the embedded and heap-based vecs have different requirements.
>>>>>>>>>
>>>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>>>>>> to be put on hold until the rats nest above is untangled.  It 
>>>>>>>>> won't
>>>>>>>>> make anything worse than it is.  (I have a project that depends on
>>>>>>>>> a sane auto_vec working).
>>>>>>>>>
>>>>>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>>>>>> write an equivalent vector class just for GCC.
>>>>>>>>
>>>>>>>> It occurs to me that another way to work around the issue of 
>>>>>>>> passing
>>>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
>>>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This 
>>>>>>>> would
>>>>>>>> mean if you want to pass an auto_vec to a vec interface, it 
>>>>>>>> needs to
>>>>>>>> be by reference.  We might as well do the same for operator=, 
>>>>>>>> though
>>>>>>>> that isn't as important.
>>>>>>>
>>>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
>>>>>>> of this change.  Since the auto_vec copy ctor and assignment have
>>>>>>> been deleted by someone else in the interim, this patch doesn't
>>>>>>> reverse that.  I will propose it separately after these changes
>>>>>>> are finalized.
>>>>>>>
>>>>>>> My approach was to 1) disable the auto_vec to vec conversion,
>>>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>>>>>>> explicitly, and 3) resolve compilation errors by either changing
>>>>>>> APIs to take a vec by reference or callers to convert auto_vec to
>>>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>>>>>>> improving the const-correctness of the APIs.
>>>>>>
>>>>>> What did you base the choice between reference or to_vec on?  For
>>>>>> instance, it seems like c_parser_declaration_or_fndef could use a
>>>>>> reference, but you changed the callers instead.
>>>>>
>>>>> I went with a reference whenever I could.  That doesn't work when
>>>>> there are callers that pass in a vNULL, so there, and in assignments,
>>>>> I used to_vec().
>>>>
>>>> Is there a way to "fix" the ugliness with vNULL?  All those functions
>>>> should be able to use const vec<>& as otherwise they'd leak memory?
>>>> Can't we pass vNULL to a const vec<>&?
>>>
>>> vNULL can bind to a const vec& (via the vec conversion ctor) but
>>> not to vec&.  The three functions that in the patch are passed
>>> vNULL modify the argument when it's not vNULL but not otherwise.
>>> An alternate design is to have them take a vec* and pass in
>>> a plain NULL (or nullptr) instead of vNULL.  That would require
>>> some surgery on the function bodies that I've been trying to
>>> avoid in the first pass.
>>
>> But I wonder if since you now identified them they could be massaged
>> prior to doing the change.
>>
>> I do hope we end up not needing .to_vec () after all, if no users 
>> remain ;)
> 
> I'd be happy to if none remained.  I see how to eliminate those in
> calls to functions like c_parser_declaration_or_fndef() (done in
> the attached revision of the patch), but no easy way to get rid
> of those that replace other implicit conversions, like all those
> assignments to the vec members of the ipa_call_arg_values ctor.
> If it's appropriate to std::move those then that would get rid
> of the .to_vec () call.  I'm not familiar with the code but I
> have the impression it might be meant more as a reference to
> some "remote" object (an instance of ipa_auto_call_arg_values?)
> If that's right then making the vec members auto_vec references
> (or pointers) would be one way to "fix" this.
> 
>>> Functions that don't leak memory now shouldn't leak with these
>>> changes, and conversely, those that do will still leak.  The patch
>>> doesn't change that (as far as I know).
>>
>> It just occurs to me those cases could pass auto_vec<>() by reference 
>> instead
>> of vNULL?  So if the vector is modified then it's released afterwards?
>> That would fix the memleak.
> 
> I see what you mean.  A function that modified the unnamed vec
> temporary constructed from vNULL then the modified vector would
> leak.  I don't think the functions the patch touches do that but
> I've removed the vNULL conversion from all of them.  There are
> many others that pass vNULL to a vec arguments that that the patch
> doesn't touch but those would be worth a closer look at some point.
> 
> Attached is a revised patch with these changes (a superset of
> those I sent in response to Jason's question), tested on x86_64.
> 
> Martin
> 
>>
>>> Going forward I think it's possible to replace most uses of vNULL
>>> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
>>> can't be readily replaced are the ones where vNULL is passed as
>>> an argument to functions taking a vec by value.  Those could be
>>> changed to avoid vNULL too, but it would take a different approach
>>> and more effort.  I'm not against it but I'd rather decouple those
>>> changes from this already sizeable patch.
>>>
>>> Martin
>>>
>>>>
>>>> Richard.
>>>>
>>>>>
>>>>> Martin
>>>>>
>>>
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-06 15:06                             ` [PING][PATCH] " Martin Sebor
@ 2021-07-07  7:28                               ` Richard Biener
  2021-07-07 14:37                                 ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Richard Biener @ 2021-07-07  7:28 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Tue, Jul 6, 2021 at 5:06 PM Martin Sebor <msebor@gmail.com> wrote:
>
> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-June/573968.html
>
> Any questions/suggestions on the final patch or is it okay to commit?

I don't remember seeing one (aka saying "bootstrapped/tested, OK to commit?"
or so) - and the link above doesn't have one.

So, can you re-post it please?

Thanks,
Richard.

> On 6/29/21 7:46 PM, Martin Sebor wrote:
> > On 6/29/21 4:58 AM, Richard Biener wrote:
> >> On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
> >>>
> >>> On 6/28/21 2:07 AM, Richard Biener wrote:
> >>>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
> >>>>>
> >>>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
> >>>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
> >>>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
> >>>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
> >>>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
> >>>>>>>>>>>> wrote:
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign
> >>>>>>>>>>>>>>> because
> >>>>>>>>>>>>>>> the class manages its own memory but doesn't define (or
> >>>>>>>>>>>>>>> delete)
> >>>>>>>>>>>>>>> either special function.  Since I first ran into the
> >>>>>>>>>>>>>>> problem,
> >>>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>>>>>>>>> assignment operator.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> The attached patch adds the two special functions to
> >>>>>>>>>>>>>>> auto_vec
> >>>>>>>>>>>>>>> along
> >>>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>>>>>>>>> containers
> >>>>>>>>>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>>>>>>>>> bootstrap
> >>>>>>>>>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> The question is whether we want such uses to appear since
> >>>>>>>>>>>>>> those
> >>>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>>>>>>>>> operators?
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> I would strongly prefer the generic vector class to have the
> >>>>>>>>>>>>> properties
> >>>>>>>>>>>>> expected of any other generic container: copyable and
> >>>>>>>>>>>>> assignable.  If
> >>>>>>>>>>>>> we also want another vector type with this restriction I
> >>>>>>>>>>>>> suggest
> >>>>>>>>>>>>> to add
> >>>>>>>>>>>>> another "noncopyable" type and make that property explicit in
> >>>>>>>>>>>>> its name.
> >>>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>>>>>>>>
> >>>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>>>>>>>>> Looking around
> >>>>>>>>>>>> I see that vec<> does not do deep copying.  Making
> >>>>>>>>>>>> auto_vec<> do it
> >>>>>>>>>>>> might be surprising (I added the move capability to match
> >>>>>>>>>>>> how vec<>
> >>>>>>>>>>>> is used - as "reference" to a vector)
> >>>>>>>>>>>
> >>>>>>>>>>> The vec base classes are special: they have no ctors at all
> >>>>>>>>>>> (because
> >>>>>>>>>>> of their use in unions).  That's something we might have to
> >>>>>>>>>>> live with
> >>>>>>>>>>> but it's not a model to follow in ordinary containers.
> >>>>>>>>>>
> >>>>>>>>>> I don't think we have to live with it anymore, now that we're
> >>>>>>>>>> writing C++11.
> >>>>>>>>>>
> >>>>>>>>>>> The auto_vec class was introduced to fill the need for a
> >>>>>>>>>>> conventional
> >>>>>>>>>>> sequence container with a ctor and dtor.  The missing copy
> >>>>>>>>>>> ctor and
> >>>>>>>>>>> assignment operators were an oversight, not a deliberate
> >>>>>>>>>>> feature.
> >>>>>>>>>>> This change fixes that oversight.
> >>>>>>>>>>>
> >>>>>>>>>>> The revised patch also adds a copy ctor/assignment to the
> >>>>>>>>>>> auto_vec
> >>>>>>>>>>> primary template (that's also missing it).  In addition, it adds
> >>>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
> >>>>>>>>>>> assignment as you prefer.
> >>>>>>>>>>
> >>>>>>>>>> Hmm, adding another class doesn't really help with the confusion
> >>>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>>>>>>>>> which will still do a shallow copy.  I think it's probably better
> >>>>>>>>>> to disable the copy special members for auto_vec until we fix
> >>>>>>>>>> vec<>.
> >>>>>>>>>
> >>>>>>>>> There are at least a couple of problems that get in the way of
> >>>>>>>>> fixing
> >>>>>>>>> all of vec to act like a well-behaved C++ container:
> >>>>>>>>>
> >>>>>>>>> 1) The embedded vec has a trailing "flexible" array member with
> >>>>>>>>> its
> >>>>>>>>> instances having different size.  They're initialized by memset
> >>>>>>>>> and
> >>>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
> >>>>>>>>> but it should disable/delete them instead.
> >>>>>>>>>
> >>>>>>>>> 2) The heap-based vec is used throughout GCC with the
> >>>>>>>>> assumption of
> >>>>>>>>> shallow copy semantics (not just as function arguments but also as
> >>>>>>>>> members of other such POD classes).  This can be changed by
> >>>>>>>>> providing
> >>>>>>>>> copy and move ctors and assignment operators for it, and also for
> >>>>>>>>> some of the classes in which it's a member and that are used with
> >>>>>>>>> the same assumption.
> >>>>>>>>>
> >>>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are
> >>>>>>>>> PODs.
> >>>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >>>>>>>>> and tree-vect-patterns.c).
> >>>>>>>>>
> >>>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
> >>>>>>>>> be a big and tricky project.  Tricky because it involves using
> >>>>>>>>> std::move in places where what's moved is subsequently still used.
> >>>>>>>>> I can keep plugging away at it but it won't change the fact that
> >>>>>>>>> the embedded and heap-based vecs have different requirements.
> >>>>>>>>>
> >>>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
> >>>>>>>>> to be put on hold until the rats nest above is untangled.  It
> >>>>>>>>> won't
> >>>>>>>>> make anything worse than it is.  (I have a project that depends on
> >>>>>>>>> a sane auto_vec working).
> >>>>>>>>>
> >>>>>>>>> A couple of alternatives to solving this are to use std::vector or
> >>>>>>>>> write an equivalent vector class just for GCC.
> >>>>>>>>
> >>>>>>>> It occurs to me that another way to work around the issue of
> >>>>>>>> passing
> >>>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
> >>>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This
> >>>>>>>> would
> >>>>>>>> mean if you want to pass an auto_vec to a vec interface, it
> >>>>>>>> needs to
> >>>>>>>> be by reference.  We might as well do the same for operator=,
> >>>>>>>> though
> >>>>>>>> that isn't as important.
> >>>>>>>
> >>>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
> >>>>>>> of this change.  Since the auto_vec copy ctor and assignment have
> >>>>>>> been deleted by someone else in the interim, this patch doesn't
> >>>>>>> reverse that.  I will propose it separately after these changes
> >>>>>>> are finalized.
> >>>>>>>
> >>>>>>> My approach was to 1) disable the auto_vec to vec conversion,
> >>>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
> >>>>>>> explicitly, and 3) resolve compilation errors by either changing
> >>>>>>> APIs to take a vec by reference or callers to convert auto_vec to
> >>>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> >>>>>>> improving the const-correctness of the APIs.
> >>>>>>
> >>>>>> What did you base the choice between reference or to_vec on?  For
> >>>>>> instance, it seems like c_parser_declaration_or_fndef could use a
> >>>>>> reference, but you changed the callers instead.
> >>>>>
> >>>>> I went with a reference whenever I could.  That doesn't work when
> >>>>> there are callers that pass in a vNULL, so there, and in assignments,
> >>>>> I used to_vec().
> >>>>
> >>>> Is there a way to "fix" the ugliness with vNULL?  All those functions
> >>>> should be able to use const vec<>& as otherwise they'd leak memory?
> >>>> Can't we pass vNULL to a const vec<>&?
> >>>
> >>> vNULL can bind to a const vec& (via the vec conversion ctor) but
> >>> not to vec&.  The three functions that in the patch are passed
> >>> vNULL modify the argument when it's not vNULL but not otherwise.
> >>> An alternate design is to have them take a vec* and pass in
> >>> a plain NULL (or nullptr) instead of vNULL.  That would require
> >>> some surgery on the function bodies that I've been trying to
> >>> avoid in the first pass.
> >>
> >> But I wonder if since you now identified them they could be massaged
> >> prior to doing the change.
> >>
> >> I do hope we end up not needing .to_vec () after all, if no users
> >> remain ;)
> >
> > I'd be happy to if none remained.  I see how to eliminate those in
> > calls to functions like c_parser_declaration_or_fndef() (done in
> > the attached revision of the patch), but no easy way to get rid
> > of those that replace other implicit conversions, like all those
> > assignments to the vec members of the ipa_call_arg_values ctor.
> > If it's appropriate to std::move those then that would get rid
> > of the .to_vec () call.  I'm not familiar with the code but I
> > have the impression it might be meant more as a reference to
> > some "remote" object (an instance of ipa_auto_call_arg_values?)
> > If that's right then making the vec members auto_vec references
> > (or pointers) would be one way to "fix" this.
> >
> >>> Functions that don't leak memory now shouldn't leak with these
> >>> changes, and conversely, those that do will still leak.  The patch
> >>> doesn't change that (as far as I know).
> >>
> >> It just occurs to me those cases could pass auto_vec<>() by reference
> >> instead
> >> of vNULL?  So if the vector is modified then it's released afterwards?
> >> That would fix the memleak.
> >
> > I see what you mean.  A function that modified the unnamed vec
> > temporary constructed from vNULL then the modified vector would
> > leak.  I don't think the functions the patch touches do that but
> > I've removed the vNULL conversion from all of them.  There are
> > many others that pass vNULL to a vec arguments that that the patch
> > doesn't touch but those would be worth a closer look at some point.
> >
> > Attached is a revised patch with these changes (a superset of
> > those I sent in response to Jason's question), tested on x86_64.
> >
> > Martin
> >
> >>
> >>> Going forward I think it's possible to replace most uses of vNULL
> >>> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
> >>> can't be readily replaced are the ones where vNULL is passed as
> >>> an argument to functions taking a vec by value.  Those could be
> >>> changed to avoid vNULL too, but it would take a different approach
> >>> and more effort.  I'm not against it but I'd rather decouple those
> >>> changes from this already sizeable patch.
> >>>
> >>> Martin
> >>>
> >>>>
> >>>> Richard.
> >>>>
> >>>>>
> >>>>> Martin
> >>>>>
> >>>
> >
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-07  7:28                               ` Richard Biener
@ 2021-07-07 14:37                                 ` Martin Sebor
  2021-07-12 11:02                                   ` Richard Biener
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-07-07 14:37 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 11980 bytes --]

On 7/7/21 1:28 AM, Richard Biener wrote:
> On Tue, Jul 6, 2021 at 5:06 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-June/573968.html
>>
>> Any questions/suggestions on the final patch or is it okay to commit?
> 
> I don't remember seeing one (aka saying "bootstrapped/tested, OK to commit?"
> or so) - and the link above doesn't have one.
> 
> So, can you re-post it please?

The patch is attached to the email above with the following text
at the end:

   Attached is a revised patch with these changes (a superset of
   those I sent in response to Jason's question), tested on x86_64.

I've also attached it to this reply.

Martin

> 
> Thanks,
> Richard.
> 
>> On 6/29/21 7:46 PM, Martin Sebor wrote:
>>> On 6/29/21 4:58 AM, Richard Biener wrote:
>>>> On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>>
>>>>> On 6/28/21 2:07 AM, Richard Biener wrote:
>>>>>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
>>>>>>>
>>>>>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
>>>>>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
>>>>>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
>>>>>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
>>>>>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
>>>>>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
>>>>>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
>>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
>>>>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
>>>>>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign
>>>>>>>>>>>>>>>>> because
>>>>>>>>>>>>>>>>> the class manages its own memory but doesn't define (or
>>>>>>>>>>>>>>>>> delete)
>>>>>>>>>>>>>>>>> either special function.  Since I first ran into the
>>>>>>>>>>>>>>>>> problem,
>>>>>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
>>>>>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
>>>>>>>>>>>>>>>>> assignment operator.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> The attached patch adds the two special functions to
>>>>>>>>>>>>>>>>> auto_vec
>>>>>>>>>>>>>>>>> along
>>>>>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
>>>>>>>>>>>>>>>>> containers
>>>>>>>>>>>>>>>>> that expect copyable and assignable element types and passes
>>>>>>>>>>>>>>>>> bootstrap
>>>>>>>>>>>>>>>>> and regression testing on x86_64-linux.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> The question is whether we want such uses to appear since
>>>>>>>>>>>>>>>> those
>>>>>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
>>>>>>>>>>>>>>>> operators?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I would strongly prefer the generic vector class to have the
>>>>>>>>>>>>>>> properties
>>>>>>>>>>>>>>> expected of any other generic container: copyable and
>>>>>>>>>>>>>>> assignable.  If
>>>>>>>>>>>>>>> we also want another vector type with this restriction I
>>>>>>>>>>>>>>> suggest
>>>>>>>>>>>>>>> to add
>>>>>>>>>>>>>>> another "noncopyable" type and make that property explicit in
>>>>>>>>>>>>>>> its name.
>>>>>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
>>>>>>>>>>>>>> Looking around
>>>>>>>>>>>>>> I see that vec<> does not do deep copying.  Making
>>>>>>>>>>>>>> auto_vec<> do it
>>>>>>>>>>>>>> might be surprising (I added the move capability to match
>>>>>>>>>>>>>> how vec<>
>>>>>>>>>>>>>> is used - as "reference" to a vector)
>>>>>>>>>>>>>
>>>>>>>>>>>>> The vec base classes are special: they have no ctors at all
>>>>>>>>>>>>> (because
>>>>>>>>>>>>> of their use in unions).  That's something we might have to
>>>>>>>>>>>>> live with
>>>>>>>>>>>>> but it's not a model to follow in ordinary containers.
>>>>>>>>>>>>
>>>>>>>>>>>> I don't think we have to live with it anymore, now that we're
>>>>>>>>>>>> writing C++11.
>>>>>>>>>>>>
>>>>>>>>>>>>> The auto_vec class was introduced to fill the need for a
>>>>>>>>>>>>> conventional
>>>>>>>>>>>>> sequence container with a ctor and dtor.  The missing copy
>>>>>>>>>>>>> ctor and
>>>>>>>>>>>>> assignment operators were an oversight, not a deliberate
>>>>>>>>>>>>> feature.
>>>>>>>>>>>>> This change fixes that oversight.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The revised patch also adds a copy ctor/assignment to the
>>>>>>>>>>>>> auto_vec
>>>>>>>>>>>>> primary template (that's also missing it).  In addition, it adds
>>>>>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
>>>>>>>>>>>>> assignment as you prefer.
>>>>>>>>>>>>
>>>>>>>>>>>> Hmm, adding another class doesn't really help with the confusion
>>>>>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
>>>>>>>>>>>> which will still do a shallow copy.  I think it's probably better
>>>>>>>>>>>> to disable the copy special members for auto_vec until we fix
>>>>>>>>>>>> vec<>.
>>>>>>>>>>>
>>>>>>>>>>> There are at least a couple of problems that get in the way of
>>>>>>>>>>> fixing
>>>>>>>>>>> all of vec to act like a well-behaved C++ container:
>>>>>>>>>>>
>>>>>>>>>>> 1) The embedded vec has a trailing "flexible" array member with
>>>>>>>>>>> its
>>>>>>>>>>> instances having different size.  They're initialized by memset
>>>>>>>>>>> and
>>>>>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
>>>>>>>>>>> but it should disable/delete them instead.
>>>>>>>>>>>
>>>>>>>>>>> 2) The heap-based vec is used throughout GCC with the
>>>>>>>>>>> assumption of
>>>>>>>>>>> shallow copy semantics (not just as function arguments but also as
>>>>>>>>>>> members of other such POD classes).  This can be changed by
>>>>>>>>>>> providing
>>>>>>>>>>> copy and move ctors and assignment operators for it, and also for
>>>>>>>>>>> some of the classes in which it's a member and that are used with
>>>>>>>>>>> the same assumption.
>>>>>>>>>>>
>>>>>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are
>>>>>>>>>>> PODs.
>>>>>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
>>>>>>>>>>> and tree-vect-patterns.c).
>>>>>>>>>>>
>>>>>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
>>>>>>>>>>> be a big and tricky project.  Tricky because it involves using
>>>>>>>>>>> std::move in places where what's moved is subsequently still used.
>>>>>>>>>>> I can keep plugging away at it but it won't change the fact that
>>>>>>>>>>> the embedded and heap-based vecs have different requirements.
>>>>>>>>>>>
>>>>>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
>>>>>>>>>>> to be put on hold until the rats nest above is untangled.  It
>>>>>>>>>>> won't
>>>>>>>>>>> make anything worse than it is.  (I have a project that depends on
>>>>>>>>>>> a sane auto_vec working).
>>>>>>>>>>>
>>>>>>>>>>> A couple of alternatives to solving this are to use std::vector or
>>>>>>>>>>> write an equivalent vector class just for GCC.
>>>>>>>>>>
>>>>>>>>>> It occurs to me that another way to work around the issue of
>>>>>>>>>> passing
>>>>>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
>>>>>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This
>>>>>>>>>> would
>>>>>>>>>> mean if you want to pass an auto_vec to a vec interface, it
>>>>>>>>>> needs to
>>>>>>>>>> be by reference.  We might as well do the same for operator=,
>>>>>>>>>> though
>>>>>>>>>> that isn't as important.
>>>>>>>>>
>>>>>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
>>>>>>>>> of this change.  Since the auto_vec copy ctor and assignment have
>>>>>>>>> been deleted by someone else in the interim, this patch doesn't
>>>>>>>>> reverse that.  I will propose it separately after these changes
>>>>>>>>> are finalized.
>>>>>>>>>
>>>>>>>>> My approach was to 1) disable the auto_vec to vec conversion,
>>>>>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
>>>>>>>>> explicitly, and 3) resolve compilation errors by either changing
>>>>>>>>> APIs to take a vec by reference or callers to convert auto_vec to
>>>>>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
>>>>>>>>> improving the const-correctness of the APIs.
>>>>>>>>
>>>>>>>> What did you base the choice between reference or to_vec on?  For
>>>>>>>> instance, it seems like c_parser_declaration_or_fndef could use a
>>>>>>>> reference, but you changed the callers instead.
>>>>>>>
>>>>>>> I went with a reference whenever I could.  That doesn't work when
>>>>>>> there are callers that pass in a vNULL, so there, and in assignments,
>>>>>>> I used to_vec().
>>>>>>
>>>>>> Is there a way to "fix" the ugliness with vNULL?  All those functions
>>>>>> should be able to use const vec<>& as otherwise they'd leak memory?
>>>>>> Can't we pass vNULL to a const vec<>&?
>>>>>
>>>>> vNULL can bind to a const vec& (via the vec conversion ctor) but
>>>>> not to vec&.  The three functions that in the patch are passed
>>>>> vNULL modify the argument when it's not vNULL but not otherwise.
>>>>> An alternate design is to have them take a vec* and pass in
>>>>> a plain NULL (or nullptr) instead of vNULL.  That would require
>>>>> some surgery on the function bodies that I've been trying to
>>>>> avoid in the first pass.
>>>>
>>>> But I wonder if since you now identified them they could be massaged
>>>> prior to doing the change.
>>>>
>>>> I do hope we end up not needing .to_vec () after all, if no users
>>>> remain ;)
>>>
>>> I'd be happy to if none remained.  I see how to eliminate those in
>>> calls to functions like c_parser_declaration_or_fndef() (done in
>>> the attached revision of the patch), but no easy way to get rid
>>> of those that replace other implicit conversions, like all those
>>> assignments to the vec members of the ipa_call_arg_values ctor.
>>> If it's appropriate to std::move those then that would get rid
>>> of the .to_vec () call.  I'm not familiar with the code but I
>>> have the impression it might be meant more as a reference to
>>> some "remote" object (an instance of ipa_auto_call_arg_values?)
>>> If that's right then making the vec members auto_vec references
>>> (or pointers) would be one way to "fix" this.
>>>
>>>>> Functions that don't leak memory now shouldn't leak with these
>>>>> changes, and conversely, those that do will still leak.  The patch
>>>>> doesn't change that (as far as I know).
>>>>
>>>> It just occurs to me those cases could pass auto_vec<>() by reference
>>>> instead
>>>> of vNULL?  So if the vector is modified then it's released afterwards?
>>>> That would fix the memleak.
>>>
>>> I see what you mean.  A function that modified the unnamed vec
>>> temporary constructed from vNULL then the modified vector would
>>> leak.  I don't think the functions the patch touches do that but
>>> I've removed the vNULL conversion from all of them.  There are
>>> many others that pass vNULL to a vec arguments that that the patch
>>> doesn't touch but those would be worth a closer look at some point.
>>>
>>> Attached is a revised patch with these changes (a superset of
>>> those I sent in response to Jason's question), tested on x86_64.
>>>
>>> Martin
>>>
>>>>
>>>>> Going forward I think it's possible to replace most uses of vNULL
>>>>> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
>>>>> can't be readily replaced are the ones where vNULL is passed as
>>>>> an argument to functions taking a vec by value.  Those could be
>>>>> changed to avoid vNULL too, but it would take a different approach
>>>>> and more effort.  I'm not against it but I'd rather decouple those
>>>>> changes from this already sizeable patch.
>>>>>
>>>>> Martin
>>>>>
>>>>>>
>>>>>> Richard.
>>>>>>
>>>>>>>
>>>>>>> Martin
>>>>>>>
>>>>>
>>>
>>


[-- Attachment #2: gcc-auto_vec-no-convert.diff --]
[-- Type: text/x-patch, Size: 75527 bytes --]

Disable implicit conversion from auto_vec to vec.


	* c-common.c (c_build_shufflevector): Adjust to vec change.
	* c-common.h (c_build_shufflevector): Same.

gcc/c/ChangeLog:

	* c-parser.c (c_finish_omp_declare_simd): Adjust to vec change.
	(c_parser_omp_declare_simd): Same.
	* c-tree.h (c_build_function_call_vec): Same.
	* c-typeck.c (c_build_function_call_vec): Same.

gcc/ChangeLog:

	* cfgloop.h (single_likely_exit): Adjust to vec change.
	* cfgloopanal.c (single_likely_exit): Same.
	* cgraph.h (struct cgraph_node): Same.
	* cgraphclones.c (cgraph_node::create_virtual_clone): Same.
	* dominance.c (prune_bbs_to_update_dominators): Same.
	(iterate_fix_dominators): Same.
	* dominance.h (iterate_fix_dominators): Same.
	* genautomata.c (merge_states): Same.
	* genextract.c (VEC_char_to_string): Same.
	* genmatch.c (dt_node::gen_kids_1): Same.
	(walk_captures): Same.
	* gimple-ssa-store-merging.c (check_no_overlap): Same.
	* gimple.c (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* gimple.h (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* haifa-sched.c (calc_priorities): Same.
	(haifa_sched_init): Same.
	(sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* ipa-cp.c (ipa_get_indirect_edge_target_1): Same.
	(adjust_callers_for_value_intersection): Same.
	(find_more_scalar_values_for_callers_subset): Same.
	(find_more_contexts_for_caller_subset): Same.
	(find_aggregate_values_for_callers_subset): Same.
	(copy_useful_known_contexts): Same.
	* ipa-fnsummary.c (remap_edge_summaries): Same.
	(remap_freqcounting_predicate): Same.
	* ipa-inline.c (add_new_edges_to_heap): Same.
	* ipa-predicate.c (predicate::remap_after_inlining): Same.
	* ipa-predicate.h:
	* ipa-prop.c (ipa_find_agg_cst_for_param): Same.
	* ipa-prop.h (ipa_find_agg_cst_for_param): Same.
	* ira-build.c (ira_loop_tree_body_rev_postorder): Same.
	* read-rtl.c (apply_iterators): Same.
	* rtl.h (native_decode_rtx): Same.
	(native_decode_vector_rtx): Same.
	* sched-int.h (sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* simplify-rtx.c (native_decode_vector_rtx): Same.
	(native_decode_rtx): Same.
	* tree-call-cdce.c (gen_shrink_wrap_conditions): Same.
	(shrink_wrap_one_built_in_call_with_conds): Same.
	(shrink_wrap_conditional_dead_built_in_calls): Same.
	* tree-data-ref.c (create_runtime_alias_checks): Same.
	(compute_all_dependences): Same.
	* tree-data-ref.h (compute_all_dependences): Same.
	(create_runtime_alias_checks): Same.
	(index_in_loop_nest): Same.
	* tree-if-conv.c (mask_exists): Same.
	* tree-loop-distribution.c (class loop_distribution): Same.
	(loop_distribution::create_rdg_vertices): Same.
	(dump_rdg_partitions): Same.
	(debug_rdg_partitions): Same.
	(partition_contains_all_rw): Same.
	(loop_distribution::distribute_loop): Same.
	* tree-parloops.c (oacc_entry_exit_ok_1): Same.
	(oacc_entry_exit_single_gang): Same.
	* tree-ssa-loop-im.c (hoist_memory_references): Same.
	(loop_suitable_for_sm): Same.
	* tree-ssa-loop-niter.c (bound_index): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (update_ops): Same.
	(swap_ops_for_binary_stmt): Same.
	(rewrite_expr_tree): Same.
	(rewrite_expr_tree_parallel): Same.
	* tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-sccvn.h (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-structalias.c (process_all_all_constraints): Same.
	(make_constraints_to): Same.
	(find_func_aliases_for_call): Same.
	(sort_fieldstack): Same.
	(check_for_overlaps): Same.
	* tree-vect-data-refs.c (vect_check_nonzero_value): Same.
	(vect_enhance_data_refs_alignment): Same.
	(vect_check_lower_bound): Same.
	(vect_prune_runtime_alias_test_list): Same.
	(vect_permute_store_chain): Same.
	* tree-vect-loop-manip.c (vect_create_cond_for_align_checks): Same.
	(vect_create_cond_for_unequal_addrs): Same.
	(vect_create_cond_for_lower_bounds): Same.
	(vect_create_cond_for_alias_checks): Same.
	* tree-vect-slp-patterns.c (vect_normalize_conj_loc): Same.
	(vect_validate_multiplication): Same.
	* tree-vect-slp.c (vect_analyze_slp_instance): Same.
	(vect_make_slp_decision): Same.
	(vect_slp_bbs): Same.
	(duplicate_and_interleave): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	* tree-vect-stmts.c (vect_create_vectorized_demotion_stmts): Same.
	* tree-vectorizer.h (vect_permute_store_chain): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	(duplicate_and_interleave): Same.
	* tree.c (build_vector_from_ctor): Same.
	(build_vector): Same.
	(check_vector_cst): Same.
	(check_vector_cst_duplicate): Same.
	(check_vector_cst_fill): Same.
	(check_vector_cst_stepped): Same.
	* tree.h (build_vector_from_ctor): Same.
	* vec.c (test_init): New.
	(vec_c_tests): Call test_init.
	* vec.h (struct vnull): Simplify.
	(auto_vec::to_vec): New member function.
	(vl_ptr>::copy): Use value initialization.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index c4eb2b1c920..9841a320f89 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1115,8 +1115,8 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask,
    and have vector types, V0 has the same element type as V1, and the
    number of elements the result is that of MASK.  */
 tree
-c_build_shufflevector (location_t loc, tree v0, tree v1, vec<tree> mask,
-		       bool complain)
+c_build_shufflevector (location_t loc, tree v0, tree v1,
+		       const vec<tree> &mask, bool complain)
 {
   tree ret;
   bool wrap = true;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 88022d0b0a9..e43b12ae1dc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1049,7 +1049,7 @@ extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
 extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note);
 extern tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true);
 extern tree c_build_shufflevector (location_t, tree, tree,
-				   vec<tree>, bool = true);
+				   const vec<tree> &, bool = true);
 extern tree c_build_vec_convert (location_t, tree, location_t, tree, bool = true);
 
 extern void init_c_lex (void);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 27034f88f49..b77e5b4f5c0 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *, vec<c_token>,
+					   bool, bool, tree * = NULL,
+					   vec<c_token> * = NULL,
 					   bool have_attrs = false,
 					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
@@ -1774,13 +1775,12 @@ c_parser_external_declaration (c_parser *parser)
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				     NULL, vNULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> &);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -1890,11 +1890,15 @@ static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration,
-			       vec<c_token> omp_declare_simd_clauses,
-			       bool have_attrs, tree attrs,
-			       struct oacc_routine_data *oacc_routine_data,
-			       bool *fallthru_attr_p)
+			       tree *objc_foreach_object_declaration
+			       /* = NULL */,
+			       vec<c_token> *omp_declare_simd_clauses
+			       /* = NULL */,
+			       bool have_attrs /* = false */,
+			       tree attrs /* = NULL_TREE */,
+			       struct oacc_routine_data *oacc_routine_data
+			       /* = NULL */,
+			       bool *fallthru_attr_p /* = NULL */)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -2150,9 +2154,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses)
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
-				       omp_declare_simd_clauses);
+				       *omp_declare_simd_clauses);
 	  if (oacc_routine_data)
 	    c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
@@ -2250,9 +2254,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		}
 	      else
 		{
@@ -2262,9 +2266,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		  init_loc = c_parser_peek_token (parser)->location;
 		  rich_location richloc (line_table, init_loc);
 		  start_init (d, asm_name, global_bindings_p (), &richloc);
@@ -2342,7 +2346,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      warn_parm_array_mismatch (lastloc, d, parms);
 		    }
 		}
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses)
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2360,7 +2364,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		  if (parms)
 		    temp_store_parm_decls (d, parms);
 		  c_finish_omp_declare_simd (parser, d, parms,
-					     omp_declare_simd_clauses);
+					     *omp_declare_simd_clauses);
 		  if (parms)
 		    temp_pop_parm_decls ();
 		}
@@ -2496,11 +2500,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL, vNULL);
+				       true, false);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses)
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
-				   omp_declare_simd_clauses);
+				   *omp_declare_simd_clauses);
       if (oacc_routine_data)
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       location_t startloc = c_parser_peek_token (parser)->location;
@@ -5699,7 +5703,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
-					 vNULL, have_std_attrs, std_attrs,
+					 NULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
 
 	  if (last_stmt && !fallthru_attr_p)
@@ -5731,7 +5735,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, vNULL);
+					     true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -6782,7 +6786,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression, vNULL);
+					 &object_expression);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -6813,7 +6817,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression, vNULL);
+					     true, &object_expression);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -11277,7 +11281,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL, vNULL);
+					   false, true);
 	  break;
 	}
     }
@@ -17273,12 +17277,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, false, NULL, &data);
+					 NULL, NULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, false, NULL, &data);
+				       NULL, NULL, false, NULL, &data);
     }
 }
 
@@ -18383,8 +18387,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
 	  this_pre_body = push_stmt_list ();
 	  c_in_omp_for = true;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, vNULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true);
 	  c_in_omp_for = false;
 	  if (this_pre_body)
 	    {
@@ -20325,12 +20328,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, &clauses);
       break;
     case pragma_struct:
     case pragma_param:
@@ -20351,7 +20354,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, &clauses);
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20360,7 +20363,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20841,7 +20844,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> &clauses)
 {
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a671a3eb740..ab6db3860f5 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -759,8 +759,9 @@ extern tree c_finish_omp_clauses (tree, enum c_omp_region_type);
 extern tree c_build_va_arg (location_t, tree, location_t, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
-extern tree c_build_function_call_vec (location_t, vec<location_t>, tree,
-				       vec<tree, va_gc> *, vec<tree, va_gc> *);
+extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
+				       tree, vec<tree, va_gc> *,
+				       vec<tree, va_gc> *);
 extern tree c_omp_clause_copy_ctor (tree, tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d079ce4b05b..efd4810b901 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3243,7 +3243,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 /* Like build_function_call_vec, but call also resolve_overloaded_builtin.  */
 
 tree
-c_build_function_call_vec (location_t loc, vec<location_t> arg_loc,
+c_build_function_call_vec (location_t loc, const vec<location_t> &arg_loc,
 			   tree function, vec<tree, va_gc> *params,
 			   vec<tree, va_gc> *origtypes)
 {
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 5e699276c88..5c2b98db9e5 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -385,7 +385,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
 
 extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
 extern edge single_exit (const class loop *);
-extern edge single_likely_exit (class loop *loop, vec<edge>);
+extern edge single_likely_exit (class loop *loop, const vec<edge> &);
 extern unsigned num_loop_branches (const class loop *);
 
 extern edge loop_preheader_edge (const class loop *);
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index 2db46c81036..4cd73c29776 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -470,7 +470,7 @@ mark_loop_exit_edges (void)
    to noreturn call.  */
 
 edge
-single_likely_exit (class loop *loop, vec<edge> exits)
+single_likely_exit (class loop *loop, const vec<edge> &exits)
 {
   edge found = single_exit (loop);
   unsigned i;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 9f4338fdf87..8c776d6f3a8 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -949,7 +949,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
   /* Create callgraph node clone with new declaration.  The actual body will be
      copied later at compilation stage.  The name of the new clone will be
      constructed from the name of the original node, SUFFIX and NUM_SUFFIX.  */
-  cgraph_node *create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+  cgraph_node *create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				     vec<ipa_replace_map *, va_gc> *tree_map,
 				     ipa_param_adjustments *param_adjustments,
 				     const char * suffix, unsigned num_suffix);
diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index 9f86463b42d..125f1b92862 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -567,7 +567,7 @@ clone_function_name (tree decl, const char *suffix)
    bitmap interface.
    */
 cgraph_node *
-cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+cgraph_node::create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				   vec<ipa_replace_map *, va_gc> *tree_map,
 				   ipa_param_adjustments *param_adjustments,
 				   const char * suffix, unsigned num_suffix)
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/genautomata.c b/gcc/genautomata.c
index 6bbfc684afa..e488c5f28ef 100644
--- a/gcc/genautomata.c
+++ b/gcc/genautomata.c
@@ -6137,7 +6137,7 @@ evaluate_equiv_classes (automaton_t automaton, vec<state_t> *equiv_classes)
 
 /* The function merges equivalent states of AUTOMATON.  */
 static void
-merge_states (automaton_t automaton, vec<state_t> equiv_classes)
+merge_states (automaton_t automaton, const vec<state_t> &equiv_classes)
 {
   state_t curr_state;
   state_t new_state;
diff --git a/gcc/genextract.c b/gcc/genextract.c
index 6fe4a2524fc..3ed2f6846c9 100644
--- a/gcc/genextract.c
+++ b/gcc/genextract.c
@@ -214,7 +214,7 @@ VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
    to a NUL-terminated string in malloc memory.  */
 static char *
-VEC_char_to_string (vec<char> v)
+VEC_char_to_string (const vec<char> &v)
 {
   size_t n = v.length ();
   char *s = XNEWVEC (char, n + 1);
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 4d476720c9e..dfd793d1f9b 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1628,8 +1628,9 @@ public:
 
   void gen_kids (FILE *, int, bool, int);
   void gen_kids_1 (FILE *, int, bool, int,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_operand *>,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_node *>);
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_node *> &);
 
   void analyze (sinfo_map_t &);
 };
@@ -2979,12 +2980,12 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
 
 void
 dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
-		     vec<dt_operand *> gimple_exprs,
-		     vec<dt_operand *> generic_exprs,
-		     vec<dt_operand *> fns,
-		     vec<dt_operand *> generic_fns,
-		     vec<dt_operand *> preds,
-		     vec<dt_node *> others)
+		     const vec<dt_operand *> &gimple_exprs,
+		     const vec<dt_operand *> &generic_exprs,
+		     const vec<dt_operand *> &fns,
+		     const vec<dt_operand *> &generic_fns,
+		     const vec<dt_operand *> &preds,
+		     const vec<dt_node *> &others)
 {
   char buf[128];
   char *kid_opname = buf;
@@ -5027,7 +5028,7 @@ parser::parse_pattern ()
    recursively.  */
 
 static void
-walk_captures (operand *op, vec<vec<capture *> > cpts)
+walk_captures (operand *op, vec<vec<capture *> > &cpts)
 {
   if (! op)
     return;
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 632947950e4..02ce068d9cf 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -2654,7 +2654,8 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
    go after the = _5 store and thus change behavior.  */
 
 static bool
-check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
+check_no_overlap (const vec<store_immediate_info *> &m_store_info,
+		  unsigned int i,
 		  bool all_integer_cst_p, unsigned int first_order,
 		  unsigned int last_order, unsigned HOST_WIDE_INT start,
 		  unsigned HOST_WIDE_INT end, unsigned int first_earlier,
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f1044e9c630..108daeda43b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -241,7 +241,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_vec (tree fn, vec<tree> args)
+gimple_build_call_vec (tree fn, const vec<tree> &args)
 {
   unsigned i;
   unsigned nargs = args.length ();
@@ -338,7 +338,7 @@ gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args)
+gimple_build_call_internal_vec (enum internal_fn fn, const vec<tree> &args)
 {
   unsigned i, nargs;
   gcall *call;
@@ -802,7 +802,7 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
    ARGS is a vector of labels excluding the default.  */
 
 gswitch *
-gimple_build_switch (tree index, tree default_label, vec<tree> args)
+gimple_build_switch (tree index, tree default_label, const vec<tree> &args)
 {
   unsigned i, nlabels = args.length ();
 
@@ -3049,7 +3049,7 @@ compare_case_labels (const void *p1, const void *p2)
 /* Sort the case labels in LABEL_VEC in place in ascending order.  */
 
 void
-sort_case_labels (vec<tree> label_vec)
+sort_case_labels (vec<tree> &label_vec)
 {
   label_vec.qsort (compare_case_labels);
 }
@@ -3074,7 +3074,7 @@ sort_case_labels (vec<tree> label_vec)
    found or not.  */
 
 void
-preprocess_case_label_vec_for_gimple (vec<tree> labels,
+preprocess_case_label_vec_for_gimple (vec<tree> &labels,
 				      tree index_type,
 				      tree *default_casep)
 {
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e7dc2a45a13..aabf68eaea0 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1516,11 +1516,11 @@ void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
-gcall *gimple_build_call_vec (tree, vec<tree> );
+gcall *gimple_build_call_vec (tree, const vec<tree> &);
 gcall *gimple_build_call (tree, unsigned, ...);
 gcall *gimple_build_call_valist (tree, unsigned, va_list);
 gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
-gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
+gcall *gimple_build_call_internal_vec (enum internal_fn, const vec<tree> &);
 gcall *gimple_build_call_from_tree (tree, tree);
 gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
@@ -1547,7 +1547,7 @@ gtry *gimple_build_try (gimple_seq, gimple_seq,
 gimple *gimple_build_wce (gimple_seq);
 gresx *gimple_build_resx (int);
 gswitch *gimple_build_switch_nlabels (unsigned, tree, tree);
-gswitch *gimple_build_switch (tree, tree, vec<tree> );
+gswitch *gimple_build_switch (tree, tree, const vec<tree> &);
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
@@ -1626,8 +1626,8 @@ extern bool nonbarrier_call_p (gimple *);
 extern bool infer_nonnull_range (gimple *, tree);
 extern bool infer_nonnull_range_by_dereference (gimple *, tree);
 extern bool infer_nonnull_range_by_attribute (gimple *, tree);
-extern void sort_case_labels (vec<tree>);
-extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
+extern void sort_case_labels (vec<tree> &);
+extern void preprocess_case_label_vec_for_gimple (vec<tree> &, tree, tree *);
 extern void gimple_seq_set_location (gimple_seq, location_t);
 extern void gimple_seq_discard (gimple_seq);
 extern void maybe_remove_unused_call_args (struct function *, gimple *);
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 9c88765d1fb..a166b706b8a 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -891,7 +891,7 @@ static void move_block_after_check (rtx_insn *);
 static void move_succs (vec<edge, va_gc> **, basic_block);
 static void sched_remove_insn (rtx_insn *);
 static void clear_priorities (rtx_insn *, rtx_vec_t *);
-static void calc_priorities (rtx_vec_t);
+static void calc_priorities (const rtx_vec_t &);
 static void add_jump_dependencies (rtx_insn *, rtx_insn *);
 
 #endif /* INSN_SCHEDULING */
@@ -7375,10 +7375,10 @@ haifa_sched_init (void)
     basic_block bb;
     FOR_EACH_BB_FN (bb, cfun)
       bbs.quick_push (bb);
-    sched_init_luids (bbs);
+    sched_init_luids (bbs.to_vec ());
     sched_deps_init (true);
     sched_extend_target ();
-    haifa_init_h_i_d (bbs);
+    haifa_init_h_i_d (bbs.to_vec ());
   }
 
   sched_init_only_bb = haifa_init_only_bb;
@@ -8923,7 +8923,7 @@ clear_priorities (rtx_insn *insn, rtx_vec_t *roots_ptr)
    changed.  ROOTS is a vector of instructions whose priority computation will
    trigger initialization of all cleared priorities.  */
 static void
-calc_priorities (rtx_vec_t roots)
+calc_priorities (const rtx_vec_t &roots)
 {
   int i;
   rtx_insn *insn;
@@ -8988,7 +8988,7 @@ sched_init_insn_luid (rtx_insn *insn)
    The hook common_sched_info->luid_for_non_insn () is used to determine
    if notes, labels, etc. need luids.  */
 void
-sched_init_luids (bb_vec_t bbs)
+sched_init_luids (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
@@ -9062,7 +9062,7 @@ init_h_i_d (rtx_insn *insn)
 
 /* Initialize haifa_insn_data for BBS.  */
 void
-haifa_init_h_i_d (bb_vec_t bbs)
+haifa_init_h_i_d (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 57c18af2bab..ce28ada19fe 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -2946,9 +2946,9 @@ propagate_constants_across_call (struct cgraph_edge *cs)
 
 static tree
 ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
-				vec<tree> known_csts,
-				vec<ipa_polymorphic_call_context> known_contexts,
-				vec<ipa_agg_value_set> known_aggs,
+				const vec<tree> &known_csts,
+				const vec<ipa_polymorphic_call_context> &known_contexts,
+				const vec<ipa_agg_value_set> &known_aggs,
 				struct ipa_agg_replacement_value *agg_reps,
 				bool *speculative)
 {
@@ -2985,7 +2985,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 	    }
 	  if (!t)
 	    {
-	      struct ipa_agg_value_set *agg;
+	      const ipa_agg_value_set *agg;
 	      if (known_aggs.length () > (unsigned int) param_index)
 		agg = &known_aggs[param_index];
 	      else
@@ -3045,7 +3045,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   if (!t && known_aggs.length () > (unsigned int) param_index
       && !ie->indirect_info->by_ref)
     {
-      struct ipa_agg_value_set *agg = &known_aggs[param_index];
+      const ipa_agg_value_set *agg = &known_aggs[param_index];
       t = ipa_find_agg_cst_for_param (agg,
 				      (unsigned) param_index
 					 < known_csts.length ()
@@ -4267,7 +4267,7 @@ get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
    this kind of adjustment is possible.  */
 
 static bool
-adjust_callers_for_value_intersection (vec<cgraph_edge *> callers,
+adjust_callers_for_value_intersection (vec<cgraph_edge *> &callers,
 				       cgraph_node *node)
 {
   for (unsigned i = 0; i < callers.length (); i++)
@@ -4725,8 +4725,8 @@ self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
 
 static void
 find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
-					    vec<tree> known_csts,
-					    vec<cgraph_edge *> callers)
+					    vec<tree> &known_csts,
+					    const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -4818,7 +4818,7 @@ static void
 find_more_contexts_for_caller_subset (cgraph_node *node,
 				      vec<ipa_polymorphic_call_context>
 				      *known_contexts,
-				      vec<cgraph_edge *> callers)
+				      const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -5179,7 +5179,7 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
 
 static struct ipa_agg_replacement_value *
 find_aggregate_values_for_callers_subset (struct cgraph_node *node,
-					  vec<cgraph_edge *> callers)
+					  const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *dest_info = ipa_node_params_sum->get (node);
   struct ipa_agg_replacement_value *res;
@@ -5413,7 +5413,7 @@ known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts)
 /* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL.  */
 
 static vec<ipa_polymorphic_call_context>
-copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts)
+copy_useful_known_contexts (const vec<ipa_polymorphic_call_context> &known_contexts)
 {
   if (known_contexts_useful_p (known_contexts))
     return known_contexts.copy ();
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 95d28757f95..cf80ce3c040 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -3967,8 +3967,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 		      class ipa_fn_summary *info,
 		      class ipa_node_params *params_summary,
 		      class ipa_fn_summary *callee_info,
-		      vec<int> operand_map,
-		      vec<HOST_WIDE_INT> offset_map,
+		      const vec<int> &operand_map,
+		      const vec<HOST_WIDE_INT> &offset_map,
 		      clause_t possible_truths,
 		      predicate *toplev_predicate)
 {
@@ -4028,8 +4028,8 @@ remap_freqcounting_predicate (class ipa_fn_summary *info,
 			      class ipa_node_params *params_summary,
 			      class ipa_fn_summary *callee_info,
 			      vec<ipa_freqcounting_predicate, va_gc> *v,
-			      vec<int> operand_map,
-			      vec<HOST_WIDE_INT> offset_map,
+			      const vec<int> &operand_map,
+			      const vec<HOST_WIDE_INT> &offset_map,
 			      clause_t possible_truths,
 			      predicate *toplev_predicate)
 
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 9d896beb2ac..413446bcc46 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1774,7 +1774,7 @@ compute_max_insns (cgraph_node *node, int insns)
 /* Compute badness of all edges in NEW_EDGES and add them to the HEAP.  */
 
 static void
-add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
+add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> &new_edges)
 {
   while (new_edges.length () > 0)
     {
diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c
index 6dd749b8ffa..e4b11ec3ae3 100644
--- a/gcc/ipa-predicate.c
+++ b/gcc/ipa-predicate.c
@@ -507,8 +507,8 @@ predicate
 predicate::remap_after_inlining (class ipa_fn_summary *info,
 				 class ipa_node_params *params_summary,
 				 class ipa_fn_summary *callee_info,
-				 vec<int> operand_map,
-				 vec<HOST_WIDE_INT> offset_map,
+				 const vec<int> &operand_map,
+				 const vec<HOST_WIDE_INT> &offset_map,
 				 clause_t possible_truths,
 				 const predicate &toplev_predicate)
 {
diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h
index 3ed71046c0c..ac52b54aa36 100644
--- a/gcc/ipa-predicate.h
+++ b/gcc/ipa-predicate.h
@@ -243,7 +243,7 @@ public:
   predicate remap_after_inlining (class ipa_fn_summary *,
 		  		  class ipa_node_params *params_summary,
 			          class ipa_fn_summary *,
-				  vec<int>, vec<HOST_WIDE_INT>,
+				  const vec<int> &, const vec<HOST_WIDE_INT> &,
 				  clause_t, const predicate &);
 
   void stream_in (class lto_input_block *);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index f74d2e17b69..43f46a578c6 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -3562,7 +3562,7 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
    initializer of a constant.  */
 
 tree
-ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 			    HOST_WIDE_INT offset, bool by_ref,
 			    bool *from_global_constant)
 {
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 3d28a6e8640..d1cd42263f5 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
@@ -1092,7 +1092,7 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value,
 void ipa_analyze_node (struct cgraph_node *);
 
 /* Aggregate jump function related functions.  */
-tree ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 				 HOST_WIDE_INT offset, bool by_ref,
 				 bool *from_global_constant = NULL);
 bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 4031ce18287..42120656366 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -1672,7 +1672,7 @@ finish_cost_vectors (void)
 
 static vec<ira_loop_tree_node_t>
 ira_loop_tree_body_rev_postorder (ira_loop_tree_node_t loop_node ATTRIBUTE_UNUSED,
-				  vec<ira_loop_tree_node_t> loop_preorder)
+				  const vec<ira_loop_tree_node_t> &loop_preorder)
 {
   vec<ira_loop_tree_node_t> topsort_nodes = vNULL;
   unsigned int n_loop_preorder;
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925402877ec..c6dfed80e04 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -835,7 +835,7 @@ md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
    gives the iterator associated with argument I of ONAME.  */
 
 static void
-add_overload_instance (overloaded_name *oname, vec<mapping *> iterators, rtx x)
+add_overload_instance (overloaded_name *oname, vec<mapping *> &iterators, rtx x)
 {
   /* Create the instance.  */
   overloaded_instance *instance = new overloaded_instance;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 5ed0d6dd6fa..2faf4ac4f97 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2416,9 +2416,9 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
 			       struct full_rtx_costs *);
 extern bool native_encode_rtx (machine_mode, rtx, vec<target_unit> &,
 			       unsigned int, unsigned int);
-extern rtx native_decode_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_rtx (machine_mode, const vec<target_unit> &,
 			      unsigned int);
-extern rtx native_decode_vector_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_vector_rtx (machine_mode, const vec<target_unit> &,
 				     unsigned int, unsigned int, unsigned int);
 extern poly_uint64 subreg_lsb (const_rtx);
 extern poly_uint64 subreg_size_lsb (poly_uint64, poly_uint64, poly_uint64);
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 4727ab28920..868f1eb6c89 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -43,12 +43,12 @@ extern void sched_init_bbs (void);
 
 extern void sched_extend_luids (void);
 extern void sched_init_insn_luid (rtx_insn *);
-extern void sched_init_luids (bb_vec_t);
+extern void sched_init_luids (const bb_vec_t &);
 extern void sched_finish_luids (void);
 
 extern void sched_extend_target (void);
 
-extern void haifa_init_h_i_d (bb_vec_t);
+extern void haifa_init_h_i_d (const bb_vec_t &);
 extern void haifa_finish_h_i_d (void);
 
 /* Hooks that are common to all the schedulers.  */
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index c82101c73a4..113991ddff4 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -6742,7 +6742,7 @@ native_encode_rtx (machine_mode mode, rtx x, vec<target_unit> &bytes,
    Return the vector on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_vector_rtx (machine_mode mode, const vec<target_unit> &bytes,
 			  unsigned int first_byte, unsigned int npatterns,
 			  unsigned int nelts_per_pattern)
 {
@@ -6787,7 +6787,7 @@ native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
    Return the rtx on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_rtx (machine_mode mode, const vec<target_unit> &bytes,
 		   unsigned int first_byte)
 {
   if (VECTOR_MODE_P (mode))
diff --git a/gcc/tree-call-cdce.c b/gcc/tree-call-cdce.c
index 666839755d0..d9b9b4c6e84 100644
--- a/gcc/tree-call-cdce.c
+++ b/gcc/tree-call-cdce.c
@@ -761,7 +761,7 @@ get_no_error_domain (enum built_in_function fnc)
    condition are separated by NULL tree in the vector.  */
 
 static void
-gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
+gen_shrink_wrap_conditions (gcall *bi_call, const vec<gimple *> &conds,
                             unsigned int *nconds)
 {
   gcall *call;
@@ -797,7 +797,8 @@ gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
    when it is non-null, it is called while all of the CONDS are true.  */
 
 static void
-shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
+shrink_wrap_one_built_in_call_with_conds (gcall *bi_call,
+					  const vec <gimple *> &conds,
 					  unsigned int nconds,
 					  gcall *bi_newcall = NULL)
 {
@@ -1132,7 +1133,7 @@ use_internal_fn (gcall *call)
    wrapping transformation.  */
 
 static void
-shrink_wrap_conditional_dead_built_in_calls (vec<gcall *> calls)
+shrink_wrap_conditional_dead_built_in_calls (const vec<gcall *> &calls)
 {
   unsigned i = 0;
 
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b6abd8b8de7..210ac2851a5 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -2643,7 +2643,7 @@ create_intersect_range_checks (class loop *loop, tree *cond_expr,
 
 void
 create_runtime_alias_checks (class loop *loop,
-			     vec<dr_with_seg_len_pair_t> *alias_pairs,
+			     const vec<dr_with_seg_len_pair_t> *alias_pairs,
 			     tree * cond_expr)
 {
   tree part_cond_expr;
@@ -5635,9 +5635,9 @@ compute_affine_dependence (struct data_dependence_relation *ddr,
    is small enough to be handled.  */
 
 bool
-compute_all_dependences (vec<data_reference_p> datarefs,
+compute_all_dependences (const vec<data_reference_p> &datarefs,
 			 vec<ddr_p> *dependence_relations,
-			 vec<loop_p> loop_nest,
+			 const vec<loop_p> &loop_nest,
 			 bool compute_self_and_rr)
 {
   struct data_dependence_relation *ddr;
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8001cc54f51..a0ff2a80263 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -551,9 +551,9 @@ extern struct data_dependence_relation *initialize_data_dependence_relation
 extern void compute_affine_dependence (struct data_dependence_relation *,
 				       loop_p);
 extern void compute_self_dependence (struct data_dependence_relation *);
-extern bool compute_all_dependences (vec<data_reference_p> ,
+extern bool compute_all_dependences (const vec<data_reference_p> &,
 				     vec<ddr_p> *,
-				     vec<loop_p>, bool);
+				     const vec<loop_p> &, bool);
 extern tree find_data_references_in_bb (class loop *, basic_block,
                                         vec<data_reference_p> *);
 extern unsigned int dr_alignment (innermost_loop_behavior *);
@@ -578,7 +578,8 @@ extern int data_ref_compare_tree (tree, tree);
 extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
 					   poly_uint64);
 extern void create_runtime_alias_checks (class loop *,
-					 vec<dr_with_seg_len_pair_t> *, tree*);
+					 const vec<dr_with_seg_len_pair_t> *,
+					 tree*);
 extern tree dr_direction_indicator (struct data_reference *);
 extern tree dr_zero_step_indicator (struct data_reference *);
 extern bool dr_known_forward_stride_p (struct data_reference *);
@@ -666,7 +667,7 @@ ddr_dependence_level (ddr_p ddr)
 /* Return the index of the variable VAR in the LOOP_NEST array.  */
 
 static inline int
-index_in_loop_nest (int var, vec<loop_p> loop_nest)
+index_in_loop_nest (int var, const vec<loop_p> &loop_nest)
 {
   class loop *loopi;
   int var_index;
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 345488e2a19..49e89cffa1a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -2208,7 +2208,7 @@ insert_gimplified_predicates (loop_p loop)
    mask if it was created for given SIZE and -1 otherwise.  */
 
 static int
-mask_exists (int size, vec<int> vec)
+mask_exists (int size, const vec<int> &vec)
 {
   unsigned int ix;
   int v;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 65aa1df4aba..7b715d684f5 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -527,7 +527,7 @@ class loop_distribution
 
   /* Build the vertices of the reduced dependence graph RDG.  Return false
      if that failed.  */
-  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts, loop_p loop);
+  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> &stmts, loop_p loop);
 
   /* Initialize STMTS with all the statements of LOOP.  We use topological
      order to discover all statements.  The order is important because
@@ -646,7 +646,7 @@ class loop_distribution
      statements from STMTS into separate loops.  Returns the number of
      distributed loops.  Set NB_CALLS to number of generated builtin calls.
      Set *DESTROY_P to whether LOOP needs to be destroyed.  */
-  int distribute_loop (class loop *loop, vec<gimple *> stmts,
+  int distribute_loop (class loop *loop, const vec<gimple *> &stmts,
 		       control_dependences *cd, int *nb_calls, bool *destroy_p,
 		       bool only_patterns_p);
 
@@ -699,7 +699,7 @@ bb_top_order_cmp_r (const void *x, const void *y, void *loop)
 }
 
 bool
-loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts,
+loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> &stmts,
 					loop_p loop)
 {
   int i;
@@ -1953,7 +1953,7 @@ loop_distribution::rdg_build_partitions (struct graph *rdg,
 /* Dump to FILE the PARTITIONS.  */
 
 static void
-dump_rdg_partitions (FILE *file, vec<partition *> partitions)
+dump_rdg_partitions (FILE *file, const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -1963,10 +1963,10 @@ dump_rdg_partitions (FILE *file, vec<partition *> partitions)
 }
 
 /* Debug PARTITIONS.  */
-extern void debug_rdg_partitions (vec<partition *> );
+extern void debug_rdg_partitions (const vec<partition *> &);
 
 DEBUG_FUNCTION void
-debug_rdg_partitions (vec<partition *> partitions)
+debug_rdg_partitions (const vec<partition *> &partitions)
 {
   dump_rdg_partitions (stderr, partitions);
 }
@@ -2017,7 +2017,7 @@ number_of_rw_in_partition (struct graph *rdg, partition *partition)
 
 static bool
 partition_contains_all_rw (struct graph *rdg,
-			   vec<partition *> partitions)
+			   const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -2921,7 +2921,8 @@ loop_distribution::finalize_partitions (class loop *loop,
    Set *DESTROY_P to whether LOOP needs to be destroyed.  */
 
 int
-loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts,
+loop_distribution::distribute_loop (class loop *loop,
+		 const vec<gimple *> &stmts,
 		 control_dependences *cd, int *nb_calls, bool *destroy_p,
 		 bool only_patterns_p)
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index fe1baef32a7..bb547572653 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -3713,7 +3713,7 @@ ref_conflicts_with_region (gimple_stmt_iterator gsi, ao_ref *ref,
    reduction results in REDUCTION_STORES.  */
 
 static bool
-oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_ok_1 (bitmap in_loop_bbs, const vec<basic_block> &region_bbs,
 		      reduction_info_table_type *reduction_list,
 		      bitmap reduction_stores)
 {
@@ -3828,7 +3828,8 @@ oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
    if any changes were made.  */
 
 static bool
-oacc_entry_exit_single_gang (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_single_gang (bitmap in_loop_bbs,
+			     const vec<basic_block> &region_bbs,
 			     bitmap reduction_stores)
 {
   tree gang_pos = NULL_TREE;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 7de47edbcb3..c778f7e87fd 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -2511,7 +2511,7 @@ sm_seq_valid_bb (class loop *loop, basic_block bb, tree vdef,
 
 static void
 hoist_memory_references (class loop *loop, bitmap mem_refs,
-			 vec<edge> exits)
+			 const vec<edge> &exits)
 {
   im_mem_ref *ref;
   unsigned  i;
@@ -2906,7 +2906,7 @@ find_refs_for_sm (class loop *loop, bitmap sm_executed, bitmap refs_to_sm)
 
 static bool
 loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
-		      vec<edge> exits)
+		      const vec<edge> &exits)
 {
   unsigned i;
   edge ex;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index b5add827018..3f9954c88a3 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3929,7 +3929,7 @@ wide_int_cmp (const void *p1, const void *p2)
    Lookup by binary search.  */
 
 static int
-bound_index (vec<widest_int> bounds, const widest_int &bound)
+bound_index (const vec<widest_int> &bounds, const widest_int &bound)
 {
   unsigned int end = bounds.length ();
   unsigned int begin = 0;
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index d86fe26bd07..a715cddc13d 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3100,7 +3100,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    vec<pre_expr> avail)
+			    vec<pre_expr> &avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 2dd4435b981..8498cfc7aa8 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -4486,7 +4486,7 @@ get_ops (tree var, enum tree_code code, vec<operand_entry *> *ops,
    stmts.  */
 
 static tree
-update_ops (tree var, enum tree_code code, vec<operand_entry *> ops,
+update_ops (tree var, enum tree_code code, const vec<operand_entry *> &ops,
 	    unsigned int *pidx, class loop *loop)
 {
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5033,7 +5033,7 @@ remove_visited_stmt_chain (tree var)
    cases, but it is unlikely to be worth it.  */
 
 static void
-swap_ops_for_binary_stmt (vec<operand_entry *> ops,
+swap_ops_for_binary_stmt (const vec<operand_entry *> &ops,
 			  unsigned int opindex, gimple *stmt)
 {
   operand_entry *oe1, *oe2, *oe3;
@@ -5104,7 +5104,8 @@ insert_stmt_before_use (gimple *stmt, gimple *stmt_to_insert)
 
 static tree
 rewrite_expr_tree (gimple *stmt, enum tree_code rhs_code, unsigned int opindex,
-		   vec<operand_entry *> ops, bool changed, bool next_changed)
+		   const vec<operand_entry *> &ops, bool changed,
+		   bool next_changed)
 {
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -5326,7 +5327,7 @@ get_reassociation_width (int ops_num, enum tree_code opc,
 
 static void
 rewrite_expr_tree_parallel (gassign *stmt, int width,
-			    vec<operand_entry *> ops)
+			    const vec<operand_entry *> &ops)
 {
   enum tree_code opcode = gimple_assign_rhs_code (stmt);
   int op_num = ops.length ();
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 64e3a707f5c..3451ff1f157 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1040,9 +1040,8 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
 bool
 ao_ref_init_from_vn_reference (ao_ref *ref,
 			       alias_set_type set, alias_set_type base_set,
-			       tree type, vec<vn_reference_op_s> ops)
+			       tree type, const vec<vn_reference_op_s> &ops)
 {
-  vn_reference_op_t op;
   unsigned i;
   tree base = NULL_TREE;
   tree *op0_p = &base;
@@ -1061,7 +1060,10 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
     size = wi::to_poly_offset (size_tree);
 
   /* Lower the final access size from the outermost expression.  */
-  op = &ops[0];
+  const_vn_reference_op_t cst_op = &ops[0];
+  /* Cast away constness for the sake of the const-unsafe
+     FOR_EACH_VEC_ELT().  */
+  vn_reference_op_t op = const_cast<vn_reference_op_t>(cst_op);
   size_tree = NULL_TREE;
   if (op->opcode == COMPONENT_REF)
     size_tree = DECL_SIZE (op->op0);
@@ -1092,7 +1094,7 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
 	      && op->op0
 	      && DECL_P (TREE_OPERAND (op->op0, 0)))
 	    {
-	      vn_reference_op_t pop = &ops[i-1];
+	      const_vn_reference_op_t pop = &ops[i-1];
 	      base = TREE_OPERAND (op->op0, 0);
 	      if (known_eq (pop->off, -1))
 		{
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 6df526c269b..96100596d2e 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -254,7 +254,7 @@ tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
 vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
 				       tree, tree *, tree, unsigned int);
 bool ao_ref_init_from_vn_reference (ao_ref *, alias_set_type, alias_set_type,
-				    tree, vec<vn_reference_op_s> );
+				    tree, const vec<vn_reference_op_s> &);
 vec<vn_reference_op_s> vn_reference_operands_for_lookup (tree);
 tree vn_reference_lookup_pieces (tree, alias_set_type, alias_set_type, tree,
 				 vec<vn_reference_op_s> ,
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 7163438e23d..e8e35362062 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3713,8 +3713,8 @@ get_constraint_for_rhs (tree t, vec<ce_s> *results)
    entries in *LHSC.  */
 
 static void
-process_all_all_constraints (vec<ce_s> lhsc,
-			     vec<ce_s> rhsc)
+process_all_all_constraints (const vec<ce_s> &lhsc,
+			     const vec<ce_s> &rhsc)
 {
   struct constraint_expr *lhsp, *rhsp;
   unsigned i, j;
@@ -3814,7 +3814,7 @@ do_structure_copy (tree lhsop, tree rhsop)
 /* Create constraints ID = { rhsc }.  */
 
 static void
-make_constraints_to (unsigned id, vec<ce_s> rhsc)
+make_constraints_to (unsigned id, const vec<ce_s> &rhsc)
 {
   struct constraint_expr *c;
   struct constraint_expr includes;
@@ -4158,7 +4158,7 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
    the LHS point to global and escaped variables.  */
 
 static void
-handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> rhsc,
+handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> &rhsc,
 		 tree fndecl)
 {
   auto_vec<ce_s> lhsc;
@@ -4609,9 +4609,10 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
       case BUILT_IN_REALLOC:
 	if (gimple_call_lhs (t))
 	  {
+	    auto_vec<ce_s> rhsc;
 	    handle_lhs_call (t, gimple_call_lhs (t),
 			     gimple_call_return_flags (t) | ERF_NOALIAS,
-			     vNULL, fndecl);
+			     rhsc, fndecl);
 	    get_constraint_for_ptr_offset (gimple_call_lhs (t),
 					   NULL_TREE, &lhsc);
 	    get_constraint_for_ptr_offset (gimple_call_arg (t, 0),
@@ -5682,7 +5683,7 @@ fieldoff_compare (const void *pa, const void *pb)
 
 /* Sort a fieldstack according to the field offset and sizes.  */
 static void
-sort_fieldstack (vec<fieldoff_s> fieldstack)
+sort_fieldstack (vec<fieldoff_s> &fieldstack)
 {
   fieldstack.qsort (fieldoff_compare);
 }
@@ -6092,7 +6093,7 @@ create_function_info_for (tree decl, const char *name, bool add_id,
    FIELDSTACK is assumed to be sorted by offset.  */
 
 static bool
-check_for_overlaps (vec<fieldoff_s> fieldstack)
+check_for_overlaps (const vec<fieldoff_s> &fieldstack)
 {
   fieldoff_s *fo = NULL;
   unsigned int i;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 579149dfd61..1e929fa002c 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -208,7 +208,7 @@ vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 static void
 vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
 {
-  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
+  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < checks.length(); ++i)
     if (checks[i] == value)
       return;
@@ -2346,7 +2346,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   if (do_versioning)
     {
       vec<stmt_vec_info> may_misalign_stmts
-        = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
+	= LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo).to_vec ();
       stmt_vec_info stmt_info;
 
       /* It can now be assumed that the data references in the statements
@@ -3360,7 +3360,8 @@ static void
 vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
 			poly_uint64 min_value)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  vec<vec_lower_bound> lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     if (operand_equal_p (lower_bounds[i].expr, expr, 0))
       {
@@ -3462,7 +3463,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
   hash_set <tree_pair_hash> compared_objects;
 
-  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
+  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).to_vec ();
   vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
     = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
   vec<vec_object_pair> &check_unequal_addrs
@@ -5335,7 +5336,7 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
    I4:  6 14 22 30  7 15 23 31.  */
 
 void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> dr_chain,
+vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
 			  unsigned int length,
 			  stmt_vec_info stmt_info,
 			  gimple_stmt_iterator *gsi,
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index 012f48bd487..9ff48fec729 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -3168,7 +3168,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
                                    tree *cond_expr,
 				   gimple_seq *cond_expr_stmt_list)
 {
-  vec<stmt_vec_info> may_misalign_stmts
+  const vec<stmt_vec_info> &may_misalign_stmts
     = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
   stmt_vec_info stmt_info;
   int mask = LOOP_VINFO_PTR_MASK (loop_vinfo);
@@ -3259,7 +3259,8 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
 static void
 vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_object_pair> pairs = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
+  const vec<vec_object_pair> &pairs
+    = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
   unsigned int i;
   vec_object_pair *pair;
   FOR_EACH_VEC_ELT (pairs, i, pair)
@@ -3278,7 +3279,8 @@ vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 static void
 vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  const vec<vec_lower_bound> &lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     {
       tree expr = lower_bounds[i].expr;
@@ -3320,7 +3322,7 @@ vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 void
 vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
 {
-  vec<dr_with_seg_len_pair_t> comp_alias_ddrs =
+  const vec<dr_with_seg_len_pair_t> &comp_alias_ddrs =
     LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
 
   if (comp_alias_ddrs.is_empty ())
diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c
index d536494a1bd..571b29322c5 100644
--- a/gcc/tree-vect-slp-patterns.c
+++ b/gcc/tree-vect-slp-patterns.c
@@ -746,7 +746,7 @@ vect_match_call_complex_mla (slp_tree node, unsigned child,
    of the negate node.  */
 
 static inline bool
-vect_normalize_conj_loc (vec<slp_tree> args, bool *neg_first_p = NULL)
+vect_normalize_conj_loc (vec<slp_tree> &args, bool *neg_first_p = NULL)
 {
   gcc_assert (args.length () == 2);
   bool neg_found = false;
@@ -790,7 +790,8 @@ is_eq_or_top (complex_perm_kinds_t perm, complex_perm_kinds_t kind)
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> left_op, vec<slp_tree> right_op,
+			      const vec<slp_tree> &left_op,
+			      const vec<slp_tree> &right_op,
 			     bool neg_first, bool *conj_first_operand,
 			     bool fms)
 {
@@ -862,7 +863,8 @@ vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> op, complex_perm_kinds_t permKind)
+			      const vec<slp_tree> &op,
+			      complex_perm_kinds_t permKind)
 {
   /* The left node is the more common case, test it first.  */
   if (!is_eq_or_top (linear_loads_p (perm_cache, op[0]), permKind))
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 227d6aa3ee8..9aee024cbf7 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -3316,7 +3316,8 @@ vect_analyze_slp_instance (vec_info *vinfo,
   else if (kind == slp_inst_kind_reduc_group)
     {
       /* Collect reduction statements.  */
-      vec<stmt_vec_info> reductions = as_a <loop_vec_info> (vinfo)->reductions;
+      const vec<stmt_vec_info> &reductions
+	= as_a <loop_vec_info> (vinfo)->reductions;
       scalar_stmts.create (reductions.length ());
       for (i = 0; reductions.iterate (i, &next_info); i++)
 	if (STMT_VINFO_RELEVANT_P (next_info)
@@ -4047,7 +4048,8 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
 {
   unsigned int i;
   poly_uint64 unrolling_factor = 1;
-  vec<slp_instance> slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
+  const vec<slp_instance> &slp_instances
+    = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
   slp_instance instance;
   int decided_to_slp = 0;
 
@@ -5814,7 +5816,7 @@ vect_slp_region (vec<basic_block> bbs, vec<data_reference_p> datarefs,
    true if anything in the basic-block was vectorized.  */
 
 static bool
-vect_slp_bbs (vec<basic_block> bbs)
+vect_slp_bbs (const vec<basic_block> &bbs)
 {
   vec<data_reference_p> datarefs = vNULL;
   auto_vec<int> dataref_groups;
@@ -5959,7 +5961,7 @@ vect_slp_function (function *fun)
 
 void
 duplicate_and_interleave (vec_info *vinfo, gimple_seq *seq, tree vector_type,
-			  vec<tree> elts, unsigned int nresults,
+			  vec<tree> &elts, unsigned int nresults,
 			  vec<tree> &results)
 {
   unsigned int nelts = elts.length ();
@@ -6315,7 +6317,7 @@ vect_get_slp_defs (vec_info *,
 
 bool
 vect_transform_slp_perm_load (vec_info *vinfo,
-			      slp_tree node, vec<tree> dr_chain,
+			      slp_tree node, const vec<tree> &dr_chain,
 			      gimple_stmt_iterator *gsi, poly_uint64 vf,
 			      bool analyze_only, unsigned *n_perms,
 			      unsigned int *n_loads, bool dce_chain)
@@ -7329,7 +7331,7 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance,
 /* Generate vector code for SLP_INSTANCES in the loop/basic block.  */
 
 void
-vect_schedule_slp (vec_info *vinfo, vec<slp_instance> slp_instances)
+vect_schedule_slp (vec_info *vinfo, const vec<slp_instance> &slp_instances)
 {
   slp_instance instance;
   unsigned int i;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 4ee11b2041a..7d99199b968 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4437,7 +4437,7 @@ static void
 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
 				       int multi_step_cvt,
 				       stmt_vec_info stmt_info,
-				       vec<tree> vec_dsts,
+				       vec<tree> &vec_dsts,
 				       gimple_stmt_iterator *gsi,
 				       slp_tree slp_node, enum tree_code code)
 {
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index fa28336d429..688bdaffcb5 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1927,8 +1927,8 @@ extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT);
 extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
 extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
 extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
-extern void vect_permute_store_chain (vec_info *,
-				      vec<tree> ,unsigned int, stmt_vec_info,
+extern void vect_permute_store_chain (vec_info *, vec<tree> &,
+				      unsigned int, stmt_vec_info,
 				      gimple_stmt_iterator *, vec<tree> *);
 extern tree vect_setup_realignment (vec_info *,
 				    stmt_vec_info, gimple_stmt_iterator *,
@@ -2009,12 +2009,12 @@ extern tree cse_and_gimplify_to_preheader (loop_vec_info, tree);
 extern void vect_slp_init (void);
 extern void vect_slp_fini (void);
 extern void vect_free_slp_instance (slp_instance);
-extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, vec<tree>,
+extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, const vec<tree> &,
 					  gimple_stmt_iterator *, poly_uint64,
 					  bool, unsigned *,
 					  unsigned * = nullptr, bool = false);
 extern bool vect_slp_analyze_operations (vec_info *);
-extern void vect_schedule_slp (vec_info *, vec<slp_instance>);
+extern void vect_schedule_slp (vec_info *, const vec<slp_instance> &);
 extern opt_result vect_analyze_slp (vec_info *, unsigned);
 extern bool vect_make_slp_decision (loop_vec_info);
 extern void vect_detect_hybrid_slp (loop_vec_info);
@@ -2032,7 +2032,7 @@ extern bool can_duplicate_and_interleave_p (vec_info *, unsigned int, tree,
 					    unsigned int * = NULL,
 					    tree * = NULL, tree * = NULL);
 extern void duplicate_and_interleave (vec_info *, gimple_seq *, tree,
-				      vec<tree>, unsigned int, vec<tree> &);
+				      vec<tree> &, unsigned int, vec<tree> &);
 extern int vect_get_place_in_interleaving_chain (stmt_vec_info, stmt_vec_info);
 extern bool vect_update_shared_vectype (stmt_vec_info, tree);
 extern slp_tree vect_create_new_slp_node (unsigned, tree_code);
diff --git a/gcc/tree.c b/gcc/tree.c
index 1aa6e557a04..bead1ac134c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2047,7 +2047,7 @@ make_vector (unsigned log2_npatterns,
    are extracted from V, a vector of CONSTRUCTOR_ELT.  */
 
 tree
-build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
+build_vector_from_ctor (tree type, const vec<constructor_elt, va_gc> *v)
 {
   if (vec_safe_length (v) == 0)
     return build_zero_cst (type);
@@ -14428,7 +14428,7 @@ test_labels ()
    are given by VALS.  */
 
 static tree
-build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
+build_vector (tree type, const vec<tree> &vals MEM_STAT_DECL)
 {
   gcc_assert (known_eq (vals.length (), TYPE_VECTOR_SUBPARTS (type)));
   tree_vector_builder builder (type, vals.length (), 1);
@@ -14439,7 +14439,7 @@ build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
 /* Check that VECTOR_CST ACTUAL contains the elements in EXPECTED.  */
 
 static void
-check_vector_cst (vec<tree> expected, tree actual)
+check_vector_cst (const vec<tree> &expected, tree actual)
 {
   ASSERT_KNOWN_EQ (expected.length (),
 		   TYPE_VECTOR_SUBPARTS (TREE_TYPE (actual)));
@@ -14452,7 +14452,7 @@ check_vector_cst (vec<tree> expected, tree actual)
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_duplicate (vec<tree> expected, tree actual,
+check_vector_cst_duplicate (const vec<tree> &expected, tree actual,
 			    unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14468,7 +14468,7 @@ check_vector_cst_duplicate (vec<tree> expected, tree actual,
    EXPECTED.  */
 
 static void
-check_vector_cst_fill (vec<tree> expected, tree actual,
+check_vector_cst_fill (const vec<tree> &expected, tree actual,
 		       unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14483,7 +14483,7 @@ check_vector_cst_fill (vec<tree> expected, tree actual,
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_stepped (vec<tree> expected, tree actual,
+check_vector_cst_stepped (const vec<tree> &expected, tree actual,
 			  unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
diff --git a/gcc/tree.h b/gcc/tree.h
index 060ddee09dd..7043ae2cddc 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4474,7 +4474,7 @@ extern tree build_int_cst (tree, poly_int64);
 extern tree build_int_cstu (tree type, poly_uint64);
 extern tree build_int_cst_type (tree, poly_int64);
 extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO);
-extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
+extern tree build_vector_from_ctor (tree, const vec<constructor_elt, va_gc> *);
 extern tree build_vector_from_val (tree, tree);
 extern tree build_uniform_cst (tree, tree);
 extern tree build_vec_series (tree, tree, tree);
diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..6d767cc12c1 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -38,16 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #endif
 
-/* vNULL is an empty type with a template cast operation that returns
-   a zero-initialized vec<T, A, L> instance.  Use this when you want
-   to assign nil values to new vec instances or pass a nil vector as
-   a function call argument.
-
-   We use this technique because vec<T, A, L> must be PODs (they are
-   stored in unions and passed in vararg functions), this means that
-   they cannot have ctors/dtors.  */
-vnull vNULL;
-
 /* Vector memory usage.  */
 class vec_usage: public mem_usage
 {
@@ -282,6 +272,42 @@ safe_push_range (vec <int>&v, int start, int limit)
     v.safe_push (i);
 }
 
+/* Verify forms of initialization.  */
+
+static void
+test_init ()
+{
+  {
+    vec<int> v1{ };
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 = vec<int>();
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 = v1;
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 (vNULL);
+    ASSERT_EQ (0, v1.length ());
+    v1.safe_push (1);
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (1, v1.length ());
+    v2.safe_push (1);
+
+    ASSERT_EQ (2, v1.length ());
+    ASSERT_EQ (2, v2.length ());
+    v1.release ();
+  }
+}
+
 /* Verify that vec::quick_push works correctly.  */
 
 static void
@@ -547,6 +573,7 @@ test_auto_delete_vec ()
 void
 vec_c_tests ()
 {
+  test_init ();
   test_quick_push ();
   test_safe_push ();
   test_truncate ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..fef3dda6a38 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -541,18 +541,16 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
     ::new (static_cast<void*>(dst)) T (*src);
 }
 
-/* Type to provide NULL values for vec<T, A, L>.  This is used to
-   provide nil initializers for vec instances.  Since vec must be
-   a POD, we cannot have proper ctor/dtor for it.  To initialize
-   a vec instance, you can assign it the value vNULL.  This isn't
-   needed for file-scope and function-local static vectors, which
-   are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
-extern vnull vNULL;
+/* Type to provide zero-initialized values for vec<T, A, L>.  This is
+   used to  provide nil initializers for vec instances.  Since vec must
+   be a trivially copyable type that can be copied by memcpy and zeroed
+   out by memset, it must have defaulted default and copy ctor and copy
+   assignment.  To initialize a vec either use value initialization
+   (e.g., vec() or vec v{ };) or assign it the value vNULL.  This isn't
+   needed for file-scope and function-local static vectors, which are
+   zero-initialized by default.  */
+struct vnull { };
+static constexpr vnull vNULL{ };
 
 
 /* Embeddable vector.  These vectors are suitable to be embedded
@@ -1431,10 +1429,34 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
    As long as we use C++03, we cannot have constructors nor
    destructors in classes that are stored in unions.  */
 
+template<typename T, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  /* Default ctors to ensure triviality.  Use value-initialization
+     (e.g., vec() or vec v{ };) or vNULL to create a zero-initialized
+     instance.  */
+  vec () = default;
+  vec (const vec &) = default;
+  /* Initialization from the generic vNULL.  */
+  vec (vnull): m_vec () { }
+  /* Same as default ctor: vec storage must be released manually.  */
+  ~vec () = default;
+
+  /* Defaulted same as copy ctor.  */
+  vec& operator= (const vec &) = default;
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1544,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1571,13 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1631,13 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // 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 ().
@@ -1781,7 +1817,7 @@ template<typename T>
 inline vec<T, va_heap, vl_ptr>
 vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
 {
-  vec<T, va_heap, vl_ptr> new_vec = vNULL;
+  vec<T, va_heap, vl_ptr> new_vec{ };
   if (length ())
     new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT);
   return new_vec;

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-07 14:37                                 ` Martin Sebor
@ 2021-07-12 11:02                                   ` Richard Biener
  2021-07-13 14:08                                     ` Jonathan Wakely
  2021-07-14 14:44                                     ` Martin Sebor
  0 siblings, 2 replies; 59+ messages in thread
From: Richard Biener @ 2021-07-12 11:02 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

On Wed, Jul 7, 2021 at 4:37 PM Martin Sebor <msebor@gmail.com> wrote:
>
> On 7/7/21 1:28 AM, Richard Biener wrote:
> > On Tue, Jul 6, 2021 at 5:06 PM Martin Sebor <msebor@gmail.com> wrote:
> >>
> >> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-June/573968.html
> >>
> >> Any questions/suggestions on the final patch or is it okay to commit?
> >
> > I don't remember seeing one (aka saying "bootstrapped/tested, OK to commit?"
> > or so) - and the link above doesn't have one.
> >
> > So, can you re-post it please?
>
> The patch is attached to the email above with the following text
> at the end:
>
>    Attached is a revised patch with these changes (a superset of
>    those I sent in response to Jason's question), tested on x86_64.
>
> I've also attached it to this reply.

Thanks - I was confused about the pipermail way of referencing attachments ...

The pieces where you change vec<> passing to const vec<>& and the few
where you change vec<> * to const vec<> * are OK - this should make the
rest a smaller piece to review.  In general const correctness changes should
be considered obvious (vec<> to const vec<>& passing isn't quite obvious
so I acked the cases explicitely).

I think the vec<> -> vec<>& cases would either benefit from constification
of callers that make using const vec<>& not possible or from a change to
pass array_slice<> (not array_slice<>&), noting that the vec<> contents
are mutated but the vec<> size does not change.

Somebody with more C++ knowledge than me needs to approve the
vec.h changes - I don't feel competent to assess all effects of the change.

Thanks,
Richard.

> Martin
>
> >
> > Thanks,
> > Richard.
> >
> >> On 6/29/21 7:46 PM, Martin Sebor wrote:
> >>> On 6/29/21 4:58 AM, Richard Biener wrote:
> >>>> On Mon, Jun 28, 2021 at 8:07 PM Martin Sebor <msebor@gmail.com> wrote:
> >>>>>
> >>>>> On 6/28/21 2:07 AM, Richard Biener wrote:
> >>>>>> On Sat, Jun 26, 2021 at 12:36 AM Martin Sebor <msebor@gmail.com> wrote:
> >>>>>>>
> >>>>>>> On 6/25/21 4:11 PM, Jason Merrill wrote:
> >>>>>>>> On 6/25/21 4:51 PM, Martin Sebor wrote:
> >>>>>>>>> On 6/1/21 3:38 PM, Jason Merrill wrote:
> >>>>>>>>>> On 6/1/21 3:56 PM, Martin Sebor wrote:
> >>>>>>>>>>> On 5/27/21 2:53 PM, Jason Merrill wrote:
> >>>>>>>>>>>> On 4/27/21 11:52 AM, Martin Sebor via Gcc-patches wrote:
> >>>>>>>>>>>>> On 4/27/21 8:04 AM, Richard Biener wrote:
> >>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 3:59 PM Martin Sebor <msebor@gmail.com>
> >>>>>>>>>>>>>> wrote:
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> On 4/27/21 1:58 AM, Richard Biener wrote:
> >>>>>>>>>>>>>>>> On Tue, Apr 27, 2021 at 2:46 AM Martin Sebor via Gcc-patches
> >>>>>>>>>>>>>>>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> PR 90904 notes that auto_vec is unsafe to copy and assign
> >>>>>>>>>>>>>>>>> because
> >>>>>>>>>>>>>>>>> the class manages its own memory but doesn't define (or
> >>>>>>>>>>>>>>>>> delete)
> >>>>>>>>>>>>>>>>> either special function.  Since I first ran into the
> >>>>>>>>>>>>>>>>> problem,
> >>>>>>>>>>>>>>>>> auto_vec has grown a move ctor and move assignment from
> >>>>>>>>>>>>>>>>> a dynamically-allocated vec but still no copy ctor or copy
> >>>>>>>>>>>>>>>>> assignment operator.
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> The attached patch adds the two special functions to
> >>>>>>>>>>>>>>>>> auto_vec
> >>>>>>>>>>>>>>>>> along
> >>>>>>>>>>>>>>>>> with a few simple tests.  It makes auto_vec safe to use in
> >>>>>>>>>>>>>>>>> containers
> >>>>>>>>>>>>>>>>> that expect copyable and assignable element types and passes
> >>>>>>>>>>>>>>>>> bootstrap
> >>>>>>>>>>>>>>>>> and regression testing on x86_64-linux.
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> The question is whether we want such uses to appear since
> >>>>>>>>>>>>>>>> those
> >>>>>>>>>>>>>>>> can be quite inefficient?  Thus the option is to delete those
> >>>>>>>>>>>>>>>> operators?
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> I would strongly prefer the generic vector class to have the
> >>>>>>>>>>>>>>> properties
> >>>>>>>>>>>>>>> expected of any other generic container: copyable and
> >>>>>>>>>>>>>>> assignable.  If
> >>>>>>>>>>>>>>> we also want another vector type with this restriction I
> >>>>>>>>>>>>>>> suggest
> >>>>>>>>>>>>>>> to add
> >>>>>>>>>>>>>>> another "noncopyable" type and make that property explicit in
> >>>>>>>>>>>>>>> its name.
> >>>>>>>>>>>>>>> I can submit one in a followup patch if you think we need one.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> I'm not sure (and not strictly against the copy and assign).
> >>>>>>>>>>>>>> Looking around
> >>>>>>>>>>>>>> I see that vec<> does not do deep copying.  Making
> >>>>>>>>>>>>>> auto_vec<> do it
> >>>>>>>>>>>>>> might be surprising (I added the move capability to match
> >>>>>>>>>>>>>> how vec<>
> >>>>>>>>>>>>>> is used - as "reference" to a vector)
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The vec base classes are special: they have no ctors at all
> >>>>>>>>>>>>> (because
> >>>>>>>>>>>>> of their use in unions).  That's something we might have to
> >>>>>>>>>>>>> live with
> >>>>>>>>>>>>> but it's not a model to follow in ordinary containers.
> >>>>>>>>>>>>
> >>>>>>>>>>>> I don't think we have to live with it anymore, now that we're
> >>>>>>>>>>>> writing C++11.
> >>>>>>>>>>>>
> >>>>>>>>>>>>> The auto_vec class was introduced to fill the need for a
> >>>>>>>>>>>>> conventional
> >>>>>>>>>>>>> sequence container with a ctor and dtor.  The missing copy
> >>>>>>>>>>>>> ctor and
> >>>>>>>>>>>>> assignment operators were an oversight, not a deliberate
> >>>>>>>>>>>>> feature.
> >>>>>>>>>>>>> This change fixes that oversight.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The revised patch also adds a copy ctor/assignment to the
> >>>>>>>>>>>>> auto_vec
> >>>>>>>>>>>>> primary template (that's also missing it).  In addition, it adds
> >>>>>>>>>>>>> a new class called auto_vec_ncopy that disables copying and
> >>>>>>>>>>>>> assignment as you prefer.
> >>>>>>>>>>>>
> >>>>>>>>>>>> Hmm, adding another class doesn't really help with the confusion
> >>>>>>>>>>>> richi mentions.  And many uses of auto_vec will pass them as vec,
> >>>>>>>>>>>> which will still do a shallow copy.  I think it's probably better
> >>>>>>>>>>>> to disable the copy special members for auto_vec until we fix
> >>>>>>>>>>>> vec<>.
> >>>>>>>>>>>
> >>>>>>>>>>> There are at least a couple of problems that get in the way of
> >>>>>>>>>>> fixing
> >>>>>>>>>>> all of vec to act like a well-behaved C++ container:
> >>>>>>>>>>>
> >>>>>>>>>>> 1) The embedded vec has a trailing "flexible" array member with
> >>>>>>>>>>> its
> >>>>>>>>>>> instances having different size.  They're initialized by memset
> >>>>>>>>>>> and
> >>>>>>>>>>> copied by memcpy.  The class can't have copy ctors or assignments
> >>>>>>>>>>> but it should disable/delete them instead.
> >>>>>>>>>>>
> >>>>>>>>>>> 2) The heap-based vec is used throughout GCC with the
> >>>>>>>>>>> assumption of
> >>>>>>>>>>> shallow copy semantics (not just as function arguments but also as
> >>>>>>>>>>> members of other such POD classes).  This can be changed by
> >>>>>>>>>>> providing
> >>>>>>>>>>> copy and move ctors and assignment operators for it, and also for
> >>>>>>>>>>> some of the classes in which it's a member and that are used with
> >>>>>>>>>>> the same assumption.
> >>>>>>>>>>>
> >>>>>>>>>>> 3) The heap-based vec::block_remove() assumes its elements are
> >>>>>>>>>>> PODs.
> >>>>>>>>>>> That breaks in VEC_ORDERED_REMOVE_IF (used in gcc/dwarf2cfi.c:2862
> >>>>>>>>>>> and tree-vect-patterns.c).
> >>>>>>>>>>>
> >>>>>>>>>>> I took a stab at both and while (1) is easy, (2) is shaping up to
> >>>>>>>>>>> be a big and tricky project.  Tricky because it involves using
> >>>>>>>>>>> std::move in places where what's moved is subsequently still used.
> >>>>>>>>>>> I can keep plugging away at it but it won't change the fact that
> >>>>>>>>>>> the embedded and heap-based vecs have different requirements.
> >>>>>>>>>>>
> >>>>>>>>>>> It doesn't seem to me that having a safely copyable auto_vec needs
> >>>>>>>>>>> to be put on hold until the rats nest above is untangled.  It
> >>>>>>>>>>> won't
> >>>>>>>>>>> make anything worse than it is.  (I have a project that depends on
> >>>>>>>>>>> a sane auto_vec working).
> >>>>>>>>>>>
> >>>>>>>>>>> A couple of alternatives to solving this are to use std::vector or
> >>>>>>>>>>> write an equivalent vector class just for GCC.
> >>>>>>>>>>
> >>>>>>>>>> It occurs to me that another way to work around the issue of
> >>>>>>>>>> passing
> >>>>>>>>>> an auto_vec by value as a vec, and thus doing a shallow copy, would
> >>>>>>>>>> be to add a vec ctor taking an auto_vec, and delete that.  This
> >>>>>>>>>> would
> >>>>>>>>>> mean if you want to pass an auto_vec to a vec interface, it
> >>>>>>>>>> needs to
> >>>>>>>>>> be by reference.  We might as well do the same for operator=,
> >>>>>>>>>> though
> >>>>>>>>>> that isn't as important.
> >>>>>>>>>
> >>>>>>>>> Thanks, that sounds like a good idea.  Attached is an implementation
> >>>>>>>>> of this change.  Since the auto_vec copy ctor and assignment have
> >>>>>>>>> been deleted by someone else in the interim, this patch doesn't
> >>>>>>>>> reverse that.  I will propose it separately after these changes
> >>>>>>>>> are finalized.
> >>>>>>>>>
> >>>>>>>>> My approach was to 1) disable the auto_vec to vec conversion,
> >>>>>>>>> 2) introduce an auto_vec::to_vec() to make the conversion possible
> >>>>>>>>> explicitly, and 3) resolve compilation errors by either changing
> >>>>>>>>> APIs to take a vec by reference or callers to convert auto_vec to
> >>>>>>>>> vec explicitly by to_vec().  In (3) I tried to minimize churn while
> >>>>>>>>> improving the const-correctness of the APIs.
> >>>>>>>>
> >>>>>>>> What did you base the choice between reference or to_vec on?  For
> >>>>>>>> instance, it seems like c_parser_declaration_or_fndef could use a
> >>>>>>>> reference, but you changed the callers instead.
> >>>>>>>
> >>>>>>> I went with a reference whenever I could.  That doesn't work when
> >>>>>>> there are callers that pass in a vNULL, so there, and in assignments,
> >>>>>>> I used to_vec().
> >>>>>>
> >>>>>> Is there a way to "fix" the ugliness with vNULL?  All those functions
> >>>>>> should be able to use const vec<>& as otherwise they'd leak memory?
> >>>>>> Can't we pass vNULL to a const vec<>&?
> >>>>>
> >>>>> vNULL can bind to a const vec& (via the vec conversion ctor) but
> >>>>> not to vec&.  The three functions that in the patch are passed
> >>>>> vNULL modify the argument when it's not vNULL but not otherwise.
> >>>>> An alternate design is to have them take a vec* and pass in
> >>>>> a plain NULL (or nullptr) instead of vNULL.  That would require
> >>>>> some surgery on the function bodies that I've been trying to
> >>>>> avoid in the first pass.
> >>>>
> >>>> But I wonder if since you now identified them they could be massaged
> >>>> prior to doing the change.
> >>>>
> >>>> I do hope we end up not needing .to_vec () after all, if no users
> >>>> remain ;)
> >>>
> >>> I'd be happy to if none remained.  I see how to eliminate those in
> >>> calls to functions like c_parser_declaration_or_fndef() (done in
> >>> the attached revision of the patch), but no easy way to get rid
> >>> of those that replace other implicit conversions, like all those
> >>> assignments to the vec members of the ipa_call_arg_values ctor.
> >>> If it's appropriate to std::move those then that would get rid
> >>> of the .to_vec () call.  I'm not familiar with the code but I
> >>> have the impression it might be meant more as a reference to
> >>> some "remote" object (an instance of ipa_auto_call_arg_values?)
> >>> If that's right then making the vec members auto_vec references
> >>> (or pointers) would be one way to "fix" this.
> >>>
> >>>>> Functions that don't leak memory now shouldn't leak with these
> >>>>> changes, and conversely, those that do will still leak.  The patch
> >>>>> doesn't change that (as far as I know).
> >>>>
> >>>> It just occurs to me those cases could pass auto_vec<>() by reference
> >>>> instead
> >>>> of vNULL?  So if the vector is modified then it's released afterwards?
> >>>> That would fix the memleak.
> >>>
> >>> I see what you mean.  A function that modified the unnamed vec
> >>> temporary constructed from vNULL then the modified vector would
> >>> leak.  I don't think the functions the patch touches do that but
> >>> I've removed the vNULL conversion from all of them.  There are
> >>> many others that pass vNULL to a vec arguments that that the patch
> >>> doesn't touch but those would be worth a closer look at some point.
> >>>
> >>> Attached is a revised patch with these changes (a superset of
> >>> those I sent in response to Jason's question), tested on x86_64.
> >>>
> >>> Martin
> >>>
> >>>>
> >>>>> Going forward I think it's possible to replace most uses of vNULL
> >>>>> in GCC with direct initialization (e.g., vec<T> v{ }).  Those that
> >>>>> can't be readily replaced are the ones where vNULL is passed as
> >>>>> an argument to functions taking a vec by value.  Those could be
> >>>>> changed to avoid vNULL too, but it would take a different approach
> >>>>> and more effort.  I'm not against it but I'd rather decouple those
> >>>>> changes from this already sizeable patch.
> >>>>>
> >>>>> Martin
> >>>>>
> >>>>>>
> >>>>>> Richard.
> >>>>>>
> >>>>>>>
> >>>>>>> Martin
> >>>>>>>
> >>>>>
> >>>
> >>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-12 11:02                                   ` Richard Biener
@ 2021-07-13 14:08                                     ` Jonathan Wakely
  2021-07-13 18:37                                       ` Jason Merrill
  2021-07-14 14:44                                     ` Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Jonathan Wakely @ 2021-07-13 14:08 UTC (permalink / raw)
  To: Richard Biener; +Cc: Martin Sebor, Jason Merrill, gcc-patches

On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
> Somebody with more C++ knowledge than me needs to approve the
> vec.h changes - I don't feel competent to assess all effects of the change.

They look OK to me except for:

-extern vnull vNULL;
+static constexpr vnull vNULL{ };

Making vNULL have static linkage can make it an ODR violation to use
vNULL in templates and inline functions, because different
instantiations will refer to a different "vNULL" in each translation
unit. The extern object avoids that problem. It probably won't cause
real problems in practice but it's still technically UB.

If avoiding the extern variable is desirable, you can make it inline
when compiled by a C++17 compiler (such as GCC 11):

#if __cpp_inline_variables
inline constexpr vnull vNULL{ };
#else
extern const vnull vNULL;
#endif

and then define it in vec.c:

#if ! __cpp_inline_variables
const vnull vNULL{ };
#endif


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-13 14:08                                     ` Jonathan Wakely
@ 2021-07-13 18:37                                       ` Jason Merrill
  2021-07-13 20:02                                         ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-07-13 18:37 UTC (permalink / raw)
  To: Jonathan Wakely, Richard Biener; +Cc: Martin Sebor, gcc-patches

On 7/13/21 10:08 AM, Jonathan Wakely wrote:
> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>> Somebody with more C++ knowledge than me needs to approve the
>> vec.h changes - I don't feel competent to assess all effects of the change.
> 
> They look OK to me except for:
> 
> -extern vnull vNULL;
> +static constexpr vnull vNULL{ };
> 
> Making vNULL have static linkage can make it an ODR violation to use
> vNULL in templates and inline functions, because different
> instantiations will refer to a different "vNULL" in each translation
> unit.

The ODR says this is OK because it's a literal constant with the same 
value (6.2/12.2.1).

But it would be better without the explicit 'static'; then in C++17 it's 
implicitly inline instead of static.

But then, do we really want to keep vNULL at all?  It's a weird blurring 
of the object/pointer boundary that is also dependent on vec being a 
thin wrapper around a pointer.  In almost all cases it can be replaced 
with {}; one exception is == comparison, where it seems to be testing 
that the embedded pointer is null, which is a weird thing to want to test.

Somewhat relatedly, use of vec<T> variables or fields seems almost 
always a mistake, as they need explicit .release() that could be 
automatic with auto_vec, and is easy to forget.  For instance, the 
recursive call in get_all_loop_exits returns a vec that is never 
released.  And I see a couple of leaks in the C++ front end as well.

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-13 18:37                                       ` Jason Merrill
@ 2021-07-13 20:02                                         ` Martin Sebor
  2021-07-14  3:39                                           ` Jason Merrill
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-07-13 20:02 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/13/21 12:37 PM, Jason Merrill wrote:
> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>> Somebody with more C++ knowledge than me needs to approve the
>>> vec.h changes - I don't feel competent to assess all effects of the 
>>> change.
>>
>> They look OK to me except for:
>>
>> -extern vnull vNULL;
>> +static constexpr vnull vNULL{ };
>>
>> Making vNULL have static linkage can make it an ODR violation to use
>> vNULL in templates and inline functions, because different
>> instantiations will refer to a different "vNULL" in each translation
>> unit.
> 
> The ODR says this is OK because it's a literal constant with the same 
> value (6.2/12.2.1).
> 
> But it would be better without the explicit 'static'; then in C++17 it's 
> implicitly inline instead of static.

I'll remove the static.

> 
> But then, do we really want to keep vNULL at all?  It's a weird blurring 
> of the object/pointer boundary that is also dependent on vec being a 
> thin wrapper around a pointer.  In almost all cases it can be replaced 
> with {}; one exception is == comparison, where it seems to be testing 
> that the embedded pointer is null, which is a weird thing to want to test.

The one use case I know of for vNULL where I can't think of
an equally good substitute is in passing a vec as an argument by
value.  The only way to do that that I can think of is to name
the full vec type (i.e., the specialization) which is more typing
and less generic than vNULL.  I don't use vNULL myself so I wouldn't
miss this trick if it were to be removed but others might feel
differently.

If not, I'm all for getting rid of vNULL but with over 350 uses
of it left, unless there's some clever trick to make the removal
(mostly) effortless and seamless, I'd much rather do it independently
of this initial change. I also don't know if I can commit to making
all this cleanup.

> 
> Somewhat relatedly, use of vec<T> variables or fields seems almost 
> always a mistake, as they need explicit .release() that could be 
> automatic with auto_vec, and is easy to forget.  For instance, the 
> recursive call in get_all_loop_exits returns a vec that is never 
> released.  And I see a couple of leaks in the C++ front end as well.

I agree.  The challenge I ran into with changing vec fields is with
code that uses the vec member as a reference to auto_vec.  This is
the case in gcc/ipa-prop.h, for instance.  Those instances could
be changed to auto_vec references or pointers but again it's a more
intrusive change than the simple replacements I was planning to make
in this first iteration.

So in summary, I agree with the changes you suggest.  Given their
scope I'd prefer not to make them in the same patch, and rather make
them at some point in the future when I or someone else has the time
and energy.  I'm running out.

Martin

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-13 20:02                                         ` Martin Sebor
@ 2021-07-14  3:39                                           ` Jason Merrill
  2021-07-14 10:47                                             ` Jonathan Wakely
  2021-07-14 14:46                                             ` Martin Sebor
  0 siblings, 2 replies; 59+ messages in thread
From: Jason Merrill @ 2021-07-14  3:39 UTC (permalink / raw)
  To: Martin Sebor, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/13/21 4:02 PM, Martin Sebor wrote:
> On 7/13/21 12:37 PM, Jason Merrill wrote:
>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>> Somebody with more C++ knowledge than me needs to approve the
>>>> vec.h changes - I don't feel competent to assess all effects of the 
>>>> change.
>>>
>>> They look OK to me except for:
>>>
>>> -extern vnull vNULL;
>>> +static constexpr vnull vNULL{ };
>>>
>>> Making vNULL have static linkage can make it an ODR violation to use
>>> vNULL in templates and inline functions, because different
>>> instantiations will refer to a different "vNULL" in each translation
>>> unit.
>>
>> The ODR says this is OK because it's a literal constant with the same 
>> value (6.2/12.2.1).
>>
>> But it would be better without the explicit 'static'; then in C++17 
>> it's implicitly inline instead of static.
> 
> I'll remove the static.
> 
>>
>> But then, do we really want to keep vNULL at all?  It's a weird 
>> blurring of the object/pointer boundary that is also dependent on vec 
>> being a thin wrapper around a pointer.  In almost all cases it can be 
>> replaced with {}; one exception is == comparison, where it seems to be 
>> testing that the embedded pointer is null, which is a weird thing to 
>> want to test.
> 
> The one use case I know of for vNULL where I can't think of
> an equally good substitute is in passing a vec as an argument by
> value.  The only way to do that that I can think of is to name
> the full vec type (i.e., the specialization) which is more typing
> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
> miss this trick if it were to be removed but others might feel
> differently.

In C++11, it can be replaced by {} in that context as well.

> If not, I'm all for getting rid of vNULL but with over 350 uses
> of it left, unless there's some clever trick to make the removal
> (mostly) effortless and seamless, I'd much rather do it independently
> of this initial change. I also don't know if I can commit to making
> all this cleanup.

I already have a patch to replace all but one use of vNULL, but I'll 
hold off with it until after your patch.

>> Somewhat relatedly, use of vec<T> variables or fields seems almost 
>> always a mistake, as they need explicit .release() that could be 
>> automatic with auto_vec, and is easy to forget.  For instance, the 
>> recursive call in get_all_loop_exits returns a vec that is never 
>> released.  And I see a couple of leaks in the C++ front end as well.
> 
> I agree.  The challenge I ran into with changing vec fields is with
> code that uses the vec member as a reference to auto_vec.  This is
> the case in gcc/ipa-prop.h, for instance.  Those instances could
> be changed to auto_vec references or pointers but again it's a more
> intrusive change than the simple replacements I was planning to make
> in this first iteration.
> 
> So in summary, I agree with the changes you suggest.  Given their
> scope I'd prefer not to make them in the same patch, and rather make
> them at some point in the future when I or someone else has the time
> and energy.  I'm running out.

Oh, absolutely.

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-14  3:39                                           ` Jason Merrill
@ 2021-07-14 10:47                                             ` Jonathan Wakely
  2021-07-14 14:46                                             ` Martin Sebor
  1 sibling, 0 replies; 59+ messages in thread
From: Jonathan Wakely @ 2021-07-14 10:47 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Martin Sebor, Richard Biener, gcc-patches

On Wed, 14 Jul 2021 at 04:39, Jason Merrill <jason@redhat.com> wrote:
>
> On 7/13/21 4:02 PM, Martin Sebor wrote:
> > On 7/13/21 12:37 PM, Jason Merrill wrote:
> >> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
> >>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
> >>>> Somebody with more C++ knowledge than me needs to approve the
> >>>> vec.h changes - I don't feel competent to assess all effects of the
> >>>> change.
> >>>
> >>> They look OK to me except for:
> >>>
> >>> -extern vnull vNULL;
> >>> +static constexpr vnull vNULL{ };
> >>>
> >>> Making vNULL have static linkage can make it an ODR violation to use
> >>> vNULL in templates and inline functions, because different
> >>> instantiations will refer to a different "vNULL" in each translation
> >>> unit.
> >>
> >> The ODR says this is OK because it's a literal constant with the same
> >> value (6.2/12.2.1).
> >>
> >> But it would be better without the explicit 'static'; then in C++17
> >> it's implicitly inline instead of static.
> >
> > I'll remove the static.
> >
> >>
> >> But then, do we really want to keep vNULL at all?  It's a weird
> >> blurring of the object/pointer boundary that is also dependent on vec
> >> being a thin wrapper around a pointer.  In almost all cases it can be
> >> replaced with {}; one exception is == comparison, where it seems to be
> >> testing that the embedded pointer is null, which is a weird thing to
> >> want to test.
> >
> > The one use case I know of for vNULL where I can't think of
> > an equally good substitute is in passing a vec as an argument by
> > value.  The only way to do that that I can think of is to name
> > the full vec type (i.e., the specialization) which is more typing
> > and less generic than vNULL.  I don't use vNULL myself so I wouldn't
> > miss this trick if it were to be removed but others might feel
> > differently.
>
> In C++11, it can be replaced by {} in that context as well.

Or if people don't like that, you could add a constructor taking
std::nullptr_t and an equality comparison with std::nullptr_t and then
use nullptr instead of vNULL.

I think just using {} for an empty, value-initialized vec makes more
sense though.


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-12 11:02                                   ` Richard Biener
  2021-07-13 14:08                                     ` Jonathan Wakely
@ 2021-07-14 14:44                                     ` Martin Sebor
  1 sibling, 0 replies; 59+ messages in thread
From: Martin Sebor @ 2021-07-14 14:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jason Merrill, gcc-patches, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 2401 bytes --]

On 7/12/21 5:02 AM, Richard Biener wrote:
> On Wed, Jul 7, 2021 at 4:37 PM Martin Sebor <msebor@gmail.com> wrote:
>>
>> On 7/7/21 1:28 AM, Richard Biener wrote:
>>> On Tue, Jul 6, 2021 at 5:06 PM Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-June/573968.html
>>>>
>>>> Any questions/suggestions on the final patch or is it okay to commit?
>>>
>>> I don't remember seeing one (aka saying "bootstrapped/tested, OK to commit?"
>>> or so) - and the link above doesn't have one.
>>>
>>> So, can you re-post it please?
>>
>> The patch is attached to the email above with the following text
>> at the end:
>>
>>     Attached is a revised patch with these changes (a superset of
>>     those I sent in response to Jason's question), tested on x86_64.
>>
>> I've also attached it to this reply.
> 
> Thanks - I was confused about the pipermail way of referencing attachments ...
> 
> The pieces where you change vec<> passing to const vec<>& and the few
> where you change vec<> * to const vec<> * are OK - this should make the
> rest a smaller piece to review.  In general const correctness changes should
> be considered obvious (vec<> to const vec<>& passing isn't quite obvious
> so I acked the cases explicitely).

Okay.

> 
> I think the vec<> -> vec<>& cases would either benefit from constification
> of callers that make using const vec<>& not possible or from a change to
> pass array_slice<> (not array_slice<>&), noting that the vec<> contents
> are mutated but the vec<> size does not change.

I've reviewed the patch and found a handful of instances I had missed
where the vec& could be made const.   The rest of the vec<> -> vec<>&
changes are all to functions that modify the vec, either directly or
by passing it to other functions that do.  (I you see some you want
me to double-check let me know.)

As a reminder, there may still be APIs where an existing by-value or
by-reference vec could be made const vec& if they don't have to be
touched for other reasons (i.e., passing an auto_vec as an argument).
Those should also be reviewed at some point.

> 
> Somebody with more C++ knowledge than me needs to approve the
> vec.h changes - I don't feel competent to assess all effects of the change.

Ack.

Attached is an updated patch with a few of the vec& -> const vec&
changes and the removal of the static specifier on vNULL.

Martin

[-- Attachment #2: gcc-auto_vec-no-convert.diff --]
[-- Type: text/x-patch, Size: 75564 bytes --]

Disable implicit conversion from auto_vec to vec.


	* c-common.c (c_build_shufflevector): Adjust to vec change.
	* c-common.h (c_build_shufflevector): Same.

gcc/c/ChangeLog:

	* c-parser.c (c_finish_omp_declare_simd): Adjust to vec change.
	(c_parser_omp_declare_simd): Same.
	* c-tree.h (c_build_function_call_vec): Same.
	* c-typeck.c (c_build_function_call_vec): Same.

gcc/ChangeLog:

	* cfgloop.h (single_likely_exit): Adjust to vec change.
	* cfgloopanal.c (single_likely_exit): Same.
	* cgraph.h (struct cgraph_node): Same.
	* cgraphclones.c (cgraph_node::create_virtual_clone): Same.
	* dominance.c (prune_bbs_to_update_dominators): Same.
	(iterate_fix_dominators): Same.
	* dominance.h (iterate_fix_dominators): Same.
	* genautomata.c (merge_states): Same.
	* genextract.c (VEC_char_to_string): Same.
	* genmatch.c (dt_node::gen_kids_1): Same.
	(walk_captures): Same.
	* gimple-ssa-store-merging.c (check_no_overlap): Same.
	* gimple.c (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* gimple.h (gimple_build_call_vec): Same.
	(gimple_build_call_internal_vec): Same.
	(gimple_build_switch): Same.
	(sort_case_labels): Same.
	(preprocess_case_label_vec_for_gimple): Same.
	* haifa-sched.c (calc_priorities): Same.
	(haifa_sched_init): Same.
	(sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* ipa-cp.c (ipa_get_indirect_edge_target_1): Same.
	(adjust_callers_for_value_intersection): Same.
	(find_more_scalar_values_for_callers_subset): Same.
	(find_more_contexts_for_caller_subset): Same.
	(find_aggregate_values_for_callers_subset): Same.
	(copy_useful_known_contexts): Same.
	* ipa-fnsummary.c (remap_edge_summaries): Same.
	(remap_freqcounting_predicate): Same.
	* ipa-inline.c (add_new_edges_to_heap): Same.
	* ipa-predicate.c (predicate::remap_after_inlining): Same.
	* ipa-predicate.h:
	* ipa-prop.c (ipa_find_agg_cst_for_param): Same.
	* ipa-prop.h (ipa_find_agg_cst_for_param): Same.
	* ira-build.c (ira_loop_tree_body_rev_postorder): Same.
	* read-rtl.c (apply_iterators): Same.
	* rtl.h (native_decode_rtx): Same.
	(native_decode_vector_rtx): Same.
	* sched-int.h (sched_init_luids): Same.
	(haifa_init_h_i_d): Same.
	* simplify-rtx.c (native_decode_vector_rtx): Same.
	(native_decode_rtx): Same.
	* tree-call-cdce.c (gen_shrink_wrap_conditions): Same.
	(shrink_wrap_one_built_in_call_with_conds): Same.
	(shrink_wrap_conditional_dead_built_in_calls): Same.
	* tree-data-ref.c (create_runtime_alias_checks): Same.
	(compute_all_dependences): Same.
	* tree-data-ref.h (compute_all_dependences): Same.
	(create_runtime_alias_checks): Same.
	(index_in_loop_nest): Same.
	* tree-if-conv.c (mask_exists): Same.
	* tree-loop-distribution.c (class loop_distribution): Same.
	(loop_distribution::create_rdg_vertices): Same.
	(dump_rdg_partitions): Same.
	(debug_rdg_partitions): Same.
	(partition_contains_all_rw): Same.
	(loop_distribution::distribute_loop): Same.
	* tree-parloops.c (oacc_entry_exit_ok_1): Same.
	(oacc_entry_exit_single_gang): Same.
	* tree-ssa-loop-im.c (hoist_memory_references): Same.
	(loop_suitable_for_sm): Same.
	* tree-ssa-loop-niter.c (bound_index): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (update_ops): Same.
	(swap_ops_for_binary_stmt): Same.
	(rewrite_expr_tree): Same.
	(rewrite_expr_tree_parallel): Same.
	* tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-sccvn.h (ao_ref_init_from_vn_reference): Same.
	* tree-ssa-structalias.c (process_all_all_constraints): Same.
	(make_constraints_to): Same.
	(find_func_aliases_for_call): Same.
	(sort_fieldstack): Same.
	(check_for_overlaps): Same.
	* tree-vect-data-refs.c (vect_check_nonzero_value): Same.
	(vect_enhance_data_refs_alignment): Same.
	(vect_check_lower_bound): Same.
	(vect_prune_runtime_alias_test_list): Same.
	(vect_permute_store_chain): Same.
	* tree-vect-loop-manip.c (vect_create_cond_for_align_checks): Same.
	(vect_create_cond_for_unequal_addrs): Same.
	(vect_create_cond_for_lower_bounds): Same.
	(vect_create_cond_for_alias_checks): Same.
	* tree-vect-slp-patterns.c (vect_normalize_conj_loc): Same.
	(vect_validate_multiplication): Same.
	* tree-vect-slp.c (vect_analyze_slp_instance): Same.
	(vect_make_slp_decision): Same.
	(vect_slp_bbs): Same.
	(duplicate_and_interleave): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	* tree-vect-stmts.c (vect_create_vectorized_demotion_stmts): Same.
	* tree-vectorizer.h (vect_permute_store_chain): Same.
	(vect_transform_slp_perm_load): Same.
	(vect_schedule_slp): Same.
	(duplicate_and_interleave): Same.
	* tree.c (build_vector_from_ctor): Same.
	(build_vector): Same.
	(check_vector_cst): Same.
	(check_vector_cst_duplicate): Same.
	(check_vector_cst_fill): Same.
	(check_vector_cst_stepped): Same.
	* tree.h (build_vector_from_ctor): Same.
	* vec.c (test_init): New.
	(vec_c_tests): Call test_init.
	* vec.h (struct vnull): Simplify.
	(auto_vec::to_vec): New member function.
	(vl_ptr>::copy): Use value initialization.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index c4eb2b1c920..9841a320f89 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1115,8 +1115,8 @@ c_build_vec_perm_expr (location_t loc, tree v0, tree v1, tree mask,
    and have vector types, V0 has the same element type as V1, and the
    number of elements the result is that of MASK.  */
 tree
-c_build_shufflevector (location_t loc, tree v0, tree v1, vec<tree> mask,
-		       bool complain)
+c_build_shufflevector (location_t loc, tree v0, tree v1,
+		       const vec<tree> &mask, bool complain)
 {
   tree ret;
   bool wrap = true;
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 88022d0b0a9..e43b12ae1dc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1049,7 +1049,7 @@ extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
 extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note);
 extern tree c_build_vec_perm_expr (location_t, tree, tree, tree, bool = true);
 extern tree c_build_shufflevector (location_t, tree, tree,
-				   vec<tree>, bool = true);
+				   const vec<tree> &, bool = true);
 extern tree c_build_vec_convert (location_t, tree, location_t, tree, bool = true);
 
 extern void init_c_lex (void);
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 27034f88f49..b77e5b4f5c0 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *, vec<c_token>,
+					   bool, bool, tree * = NULL,
+					   vec<c_token> * = NULL,
 					   bool have_attrs = false,
 					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
@@ -1774,13 +1775,12 @@ c_parser_external_declaration (c_parser *parser)
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				     NULL, vNULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> &);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -1890,11 +1890,15 @@ static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration,
-			       vec<c_token> omp_declare_simd_clauses,
-			       bool have_attrs, tree attrs,
-			       struct oacc_routine_data *oacc_routine_data,
-			       bool *fallthru_attr_p)
+			       tree *objc_foreach_object_declaration
+			       /* = NULL */,
+			       vec<c_token> *omp_declare_simd_clauses
+			       /* = NULL */,
+			       bool have_attrs /* = false */,
+			       tree attrs /* = NULL_TREE */,
+			       struct oacc_routine_data *oacc_routine_data
+			       /* = NULL */,
+			       bool *fallthru_attr_p /* = NULL */)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -2150,9 +2154,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses)
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
-				       omp_declare_simd_clauses);
+				       *omp_declare_simd_clauses);
 	  if (oacc_routine_data)
 	    c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
 	  c_parser_skip_to_end_of_block_or_statement (parser);
@@ -2250,9 +2254,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		}
 	      else
 		{
@@ -2262,9 +2266,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
-					       omp_declare_simd_clauses);
+					       *omp_declare_simd_clauses);
 		  init_loc = c_parser_peek_token (parser)->location;
 		  rich_location richloc (line_table, init_loc);
 		  start_init (d, asm_name, global_bindings_p (), &richloc);
@@ -2342,7 +2346,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      warn_parm_array_mismatch (lastloc, d, parms);
 		    }
 		}
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses)
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2360,7 +2364,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		  if (parms)
 		    temp_store_parm_decls (d, parms);
 		  c_finish_omp_declare_simd (parser, d, parms,
-					     omp_declare_simd_clauses);
+					     *omp_declare_simd_clauses);
 		  if (parms)
 		    temp_pop_parm_decls ();
 		}
@@ -2496,11 +2500,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL, vNULL);
+				       true, false);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses)
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
-				   omp_declare_simd_clauses);
+				   *omp_declare_simd_clauses);
       if (oacc_routine_data)
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       location_t startloc = c_parser_peek_token (parser)->location;
@@ -5699,7 +5703,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
-					 vNULL, have_std_attrs, std_attrs,
+					 NULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
 
 	  if (last_stmt && !fallthru_attr_p)
@@ -5731,7 +5735,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, vNULL);
+					     true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -6782,7 +6786,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression, vNULL);
+					 &object_expression);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -6813,7 +6817,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression, vNULL);
+					     true, &object_expression);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -11277,7 +11281,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL, vNULL);
+					   false, true);
 	  break;
 	}
     }
@@ -17273,12 +17277,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, false, NULL, &data);
+					 NULL, NULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, false, NULL, &data);
+				       NULL, NULL, false, NULL, &data);
     }
 }
 
@@ -18383,8 +18387,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
 	  this_pre_body = push_stmt_list ();
 	  c_in_omp_for = true;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, vNULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true);
 	  c_in_omp_for = false;
 	  if (this_pre_body)
 	    {
@@ -20325,12 +20328,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, &clauses);
       break;
     case pragma_struct:
     case pragma_param:
@@ -20351,7 +20354,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, &clauses);
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20360,7 +20363,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20841,7 +20844,7 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> &clauses)
 {
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a671a3eb740..ab6db3860f5 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -759,8 +759,9 @@ extern tree c_finish_omp_clauses (tree, enum c_omp_region_type);
 extern tree c_build_va_arg (location_t, tree, location_t, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
-extern tree c_build_function_call_vec (location_t, vec<location_t>, tree,
-				       vec<tree, va_gc> *, vec<tree, va_gc> *);
+extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
+				       tree, vec<tree, va_gc> *,
+				       vec<tree, va_gc> *);
 extern tree c_omp_clause_copy_ctor (tree, tree, tree);
 
 /* Set to 0 at beginning of a function definition, set to 1 if
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d079ce4b05b..efd4810b901 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3243,7 +3243,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 /* Like build_function_call_vec, but call also resolve_overloaded_builtin.  */
 
 tree
-c_build_function_call_vec (location_t loc, vec<location_t> arg_loc,
+c_build_function_call_vec (location_t loc, const vec<location_t> &arg_loc,
 			   tree function, vec<tree, va_gc> *params,
 			   vec<tree, va_gc> *origtypes)
 {
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index 5e699276c88..5c2b98db9e5 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -385,7 +385,7 @@ extern basic_block *get_loop_body_in_custom_order (const class loop *, void *,
 
 extern auto_vec<edge> get_loop_exit_edges (const class loop *, basic_block * = NULL);
 extern edge single_exit (const class loop *);
-extern edge single_likely_exit (class loop *loop, vec<edge>);
+extern edge single_likely_exit (class loop *loop, const vec<edge> &);
 extern unsigned num_loop_branches (const class loop *);
 
 extern edge loop_preheader_edge (const class loop *);
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index 2db46c81036..4cd73c29776 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -470,7 +470,7 @@ mark_loop_exit_edges (void)
    to noreturn call.  */
 
 edge
-single_likely_exit (class loop *loop, vec<edge> exits)
+single_likely_exit (class loop *loop, const vec<edge> &exits)
 {
   edge found = single_exit (loop);
   unsigned i;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 9f4338fdf87..8c776d6f3a8 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -949,7 +949,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
   /* Create callgraph node clone with new declaration.  The actual body will be
      copied later at compilation stage.  The name of the new clone will be
      constructed from the name of the original node, SUFFIX and NUM_SUFFIX.  */
-  cgraph_node *create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+  cgraph_node *create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				     vec<ipa_replace_map *, va_gc> *tree_map,
 				     ipa_param_adjustments *param_adjustments,
 				     const char * suffix, unsigned num_suffix);
diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index 9f86463b42d..125f1b92862 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -567,7 +567,7 @@ clone_function_name (tree decl, const char *suffix)
    bitmap interface.
    */
 cgraph_node *
-cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
+cgraph_node::create_virtual_clone (const vec<cgraph_edge *> &redirect_callers,
 				   vec<ipa_replace_map *, va_gc> *tree_map,
 				   ipa_param_adjustments *param_adjustments,
 				   const char * suffix, unsigned num_suffix)
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/genautomata.c b/gcc/genautomata.c
index 6bbfc684afa..e488c5f28ef 100644
--- a/gcc/genautomata.c
+++ b/gcc/genautomata.c
@@ -6137,7 +6137,7 @@ evaluate_equiv_classes (automaton_t automaton, vec<state_t> *equiv_classes)
 
 /* The function merges equivalent states of AUTOMATON.  */
 static void
-merge_states (automaton_t automaton, vec<state_t> equiv_classes)
+merge_states (automaton_t automaton, const vec<state_t> &equiv_classes)
 {
   state_t curr_state;
   state_t new_state;
diff --git a/gcc/genextract.c b/gcc/genextract.c
index 6fe4a2524fc..3ed2f6846c9 100644
--- a/gcc/genextract.c
+++ b/gcc/genextract.c
@@ -214,7 +214,7 @@ VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
    to a NUL-terminated string in malloc memory.  */
 static char *
-VEC_char_to_string (vec<char> v)
+VEC_char_to_string (const vec<char> &v)
 {
   size_t n = v.length ();
   char *s = XNEWVEC (char, n + 1);
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 4d476720c9e..dfd793d1f9b 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1628,8 +1628,9 @@ public:
 
   void gen_kids (FILE *, int, bool, int);
   void gen_kids_1 (FILE *, int, bool, int,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_operand *>,
-		   vec<dt_operand *>, vec<dt_operand *>, vec<dt_node *>);
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_operand *> &,
+		   const vec<dt_operand *> &, const vec<dt_node *> &);
 
   void analyze (sinfo_map_t &);
 };
@@ -2979,12 +2980,12 @@ dt_node::gen_kids (FILE *f, int indent, bool gimple, int depth)
 
 void
 dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, int depth,
-		     vec<dt_operand *> gimple_exprs,
-		     vec<dt_operand *> generic_exprs,
-		     vec<dt_operand *> fns,
-		     vec<dt_operand *> generic_fns,
-		     vec<dt_operand *> preds,
-		     vec<dt_node *> others)
+		     const vec<dt_operand *> &gimple_exprs,
+		     const vec<dt_operand *> &generic_exprs,
+		     const vec<dt_operand *> &fns,
+		     const vec<dt_operand *> &generic_fns,
+		     const vec<dt_operand *> &preds,
+		     const vec<dt_node *> &others)
 {
   char buf[128];
   char *kid_opname = buf;
@@ -5027,7 +5028,7 @@ parser::parse_pattern ()
    recursively.  */
 
 static void
-walk_captures (operand *op, vec<vec<capture *> > cpts)
+walk_captures (operand *op, vec<vec<capture *> > &cpts)
 {
   if (! op)
     return;
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 632947950e4..02ce068d9cf 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -2654,7 +2654,8 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
    go after the = _5 store and thus change behavior.  */
 
 static bool
-check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
+check_no_overlap (const vec<store_immediate_info *> &m_store_info,
+		  unsigned int i,
 		  bool all_integer_cst_p, unsigned int first_order,
 		  unsigned int last_order, unsigned HOST_WIDE_INT start,
 		  unsigned HOST_WIDE_INT end, unsigned int first_earlier,
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f1044e9c630..108daeda43b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -241,7 +241,7 @@ gimple_build_call_1 (tree fn, unsigned nargs)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_vec (tree fn, vec<tree> args)
+gimple_build_call_vec (tree fn, const vec<tree> &args)
 {
   unsigned i;
   unsigned nargs = args.length ();
@@ -338,7 +338,7 @@ gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...)
    specified in vector ARGS.  */
 
 gcall *
-gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args)
+gimple_build_call_internal_vec (enum internal_fn fn, const vec<tree> &args)
 {
   unsigned i, nargs;
   gcall *call;
@@ -802,7 +802,7 @@ gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
    ARGS is a vector of labels excluding the default.  */
 
 gswitch *
-gimple_build_switch (tree index, tree default_label, vec<tree> args)
+gimple_build_switch (tree index, tree default_label, const vec<tree> &args)
 {
   unsigned i, nlabels = args.length ();
 
@@ -3049,7 +3049,7 @@ compare_case_labels (const void *p1, const void *p2)
 /* Sort the case labels in LABEL_VEC in place in ascending order.  */
 
 void
-sort_case_labels (vec<tree> label_vec)
+sort_case_labels (vec<tree> &label_vec)
 {
   label_vec.qsort (compare_case_labels);
 }
@@ -3074,7 +3074,7 @@ sort_case_labels (vec<tree> label_vec)
    found or not.  */
 
 void
-preprocess_case_label_vec_for_gimple (vec<tree> labels,
+preprocess_case_label_vec_for_gimple (vec<tree> &labels,
 				      tree index_type,
 				      tree *default_casep)
 {
diff --git a/gcc/gimple.h b/gcc/gimple.h
index e7dc2a45a13..aabf68eaea0 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1516,11 +1516,11 @@ void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
-gcall *gimple_build_call_vec (tree, vec<tree> );
+gcall *gimple_build_call_vec (tree, const vec<tree> &);
 gcall *gimple_build_call (tree, unsigned, ...);
 gcall *gimple_build_call_valist (tree, unsigned, va_list);
 gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
-gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
+gcall *gimple_build_call_internal_vec (enum internal_fn, const vec<tree> &);
 gcall *gimple_build_call_from_tree (tree, tree);
 gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
@@ -1547,7 +1547,7 @@ gtry *gimple_build_try (gimple_seq, gimple_seq,
 gimple *gimple_build_wce (gimple_seq);
 gresx *gimple_build_resx (int);
 gswitch *gimple_build_switch_nlabels (unsigned, tree, tree);
-gswitch *gimple_build_switch (tree, tree, vec<tree> );
+gswitch *gimple_build_switch (tree, tree, const vec<tree> &);
 geh_dispatch *gimple_build_eh_dispatch (int);
 gdebug *gimple_build_debug_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
 gdebug *gimple_build_debug_source_bind (tree, tree, gimple * CXX_MEM_STAT_INFO);
@@ -1626,8 +1626,8 @@ extern bool nonbarrier_call_p (gimple *);
 extern bool infer_nonnull_range (gimple *, tree);
 extern bool infer_nonnull_range_by_dereference (gimple *, tree);
 extern bool infer_nonnull_range_by_attribute (gimple *, tree);
-extern void sort_case_labels (vec<tree>);
-extern void preprocess_case_label_vec_for_gimple (vec<tree>, tree, tree *);
+extern void sort_case_labels (vec<tree> &);
+extern void preprocess_case_label_vec_for_gimple (vec<tree> &, tree, tree *);
 extern void gimple_seq_set_location (gimple_seq, location_t);
 extern void gimple_seq_discard (gimple_seq);
 extern void maybe_remove_unused_call_args (struct function *, gimple *);
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 9c88765d1fb..a166b706b8a 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -891,7 +891,7 @@ static void move_block_after_check (rtx_insn *);
 static void move_succs (vec<edge, va_gc> **, basic_block);
 static void sched_remove_insn (rtx_insn *);
 static void clear_priorities (rtx_insn *, rtx_vec_t *);
-static void calc_priorities (rtx_vec_t);
+static void calc_priorities (const rtx_vec_t &);
 static void add_jump_dependencies (rtx_insn *, rtx_insn *);
 
 #endif /* INSN_SCHEDULING */
@@ -7375,10 +7375,10 @@ haifa_sched_init (void)
     basic_block bb;
     FOR_EACH_BB_FN (bb, cfun)
       bbs.quick_push (bb);
-    sched_init_luids (bbs);
+    sched_init_luids (bbs.to_vec ());
     sched_deps_init (true);
     sched_extend_target ();
-    haifa_init_h_i_d (bbs);
+    haifa_init_h_i_d (bbs.to_vec ());
   }
 
   sched_init_only_bb = haifa_init_only_bb;
@@ -8923,7 +8923,7 @@ clear_priorities (rtx_insn *insn, rtx_vec_t *roots_ptr)
    changed.  ROOTS is a vector of instructions whose priority computation will
    trigger initialization of all cleared priorities.  */
 static void
-calc_priorities (rtx_vec_t roots)
+calc_priorities (const rtx_vec_t &roots)
 {
   int i;
   rtx_insn *insn;
@@ -8988,7 +8988,7 @@ sched_init_insn_luid (rtx_insn *insn)
    The hook common_sched_info->luid_for_non_insn () is used to determine
    if notes, labels, etc. need luids.  */
 void
-sched_init_luids (bb_vec_t bbs)
+sched_init_luids (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
@@ -9062,7 +9062,7 @@ init_h_i_d (rtx_insn *insn)
 
 /* Initialize haifa_insn_data for BBS.  */
 void
-haifa_init_h_i_d (bb_vec_t bbs)
+haifa_init_h_i_d (const bb_vec_t &bbs)
 {
   int i;
   basic_block bb;
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 57c18af2bab..ce28ada19fe 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -2946,9 +2946,9 @@ propagate_constants_across_call (struct cgraph_edge *cs)
 
 static tree
 ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
-				vec<tree> known_csts,
-				vec<ipa_polymorphic_call_context> known_contexts,
-				vec<ipa_agg_value_set> known_aggs,
+				const vec<tree> &known_csts,
+				const vec<ipa_polymorphic_call_context> &known_contexts,
+				const vec<ipa_agg_value_set> &known_aggs,
 				struct ipa_agg_replacement_value *agg_reps,
 				bool *speculative)
 {
@@ -2985,7 +2985,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 	    }
 	  if (!t)
 	    {
-	      struct ipa_agg_value_set *agg;
+	      const ipa_agg_value_set *agg;
 	      if (known_aggs.length () > (unsigned int) param_index)
 		agg = &known_aggs[param_index];
 	      else
@@ -3045,7 +3045,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   if (!t && known_aggs.length () > (unsigned int) param_index
       && !ie->indirect_info->by_ref)
     {
-      struct ipa_agg_value_set *agg = &known_aggs[param_index];
+      const ipa_agg_value_set *agg = &known_aggs[param_index];
       t = ipa_find_agg_cst_for_param (agg,
 				      (unsigned) param_index
 					 < known_csts.length ()
@@ -4267,7 +4267,7 @@ get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
    this kind of adjustment is possible.  */
 
 static bool
-adjust_callers_for_value_intersection (vec<cgraph_edge *> callers,
+adjust_callers_for_value_intersection (vec<cgraph_edge *> &callers,
 				       cgraph_node *node)
 {
   for (unsigned i = 0; i < callers.length (); i++)
@@ -4725,8 +4725,8 @@ self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
 
 static void
 find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
-					    vec<tree> known_csts,
-					    vec<cgraph_edge *> callers)
+					    vec<tree> &known_csts,
+					    const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -4818,7 +4818,7 @@ static void
 find_more_contexts_for_caller_subset (cgraph_node *node,
 				      vec<ipa_polymorphic_call_context>
 				      *known_contexts,
-				      vec<cgraph_edge *> callers)
+				      const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *info = ipa_node_params_sum->get (node);
   int i, count = ipa_get_param_count (info);
@@ -5179,7 +5179,7 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
 
 static struct ipa_agg_replacement_value *
 find_aggregate_values_for_callers_subset (struct cgraph_node *node,
-					  vec<cgraph_edge *> callers)
+					  const vec<cgraph_edge *> &callers)
 {
   ipa_node_params *dest_info = ipa_node_params_sum->get (node);
   struct ipa_agg_replacement_value *res;
@@ -5413,7 +5413,7 @@ known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts)
 /* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL.  */
 
 static vec<ipa_polymorphic_call_context>
-copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts)
+copy_useful_known_contexts (const vec<ipa_polymorphic_call_context> &known_contexts)
 {
   if (known_contexts_useful_p (known_contexts))
     return known_contexts.copy ();
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 95d28757f95..cf80ce3c040 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -3967,8 +3967,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 		      class ipa_fn_summary *info,
 		      class ipa_node_params *params_summary,
 		      class ipa_fn_summary *callee_info,
-		      vec<int> operand_map,
-		      vec<HOST_WIDE_INT> offset_map,
+		      const vec<int> &operand_map,
+		      const vec<HOST_WIDE_INT> &offset_map,
 		      clause_t possible_truths,
 		      predicate *toplev_predicate)
 {
@@ -4028,8 +4028,8 @@ remap_freqcounting_predicate (class ipa_fn_summary *info,
 			      class ipa_node_params *params_summary,
 			      class ipa_fn_summary *callee_info,
 			      vec<ipa_freqcounting_predicate, va_gc> *v,
-			      vec<int> operand_map,
-			      vec<HOST_WIDE_INT> offset_map,
+			      const vec<int> &operand_map,
+			      const vec<HOST_WIDE_INT> &offset_map,
 			      clause_t possible_truths,
 			      predicate *toplev_predicate)
 
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 9d896beb2ac..413446bcc46 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -1774,7 +1774,7 @@ compute_max_insns (cgraph_node *node, int insns)
 /* Compute badness of all edges in NEW_EDGES and add them to the HEAP.  */
 
 static void
-add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
+add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> &new_edges)
 {
   while (new_edges.length () > 0)
     {
diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c
index 6dd749b8ffa..e4b11ec3ae3 100644
--- a/gcc/ipa-predicate.c
+++ b/gcc/ipa-predicate.c
@@ -507,8 +507,8 @@ predicate
 predicate::remap_after_inlining (class ipa_fn_summary *info,
 				 class ipa_node_params *params_summary,
 				 class ipa_fn_summary *callee_info,
-				 vec<int> operand_map,
-				 vec<HOST_WIDE_INT> offset_map,
+				 const vec<int> &operand_map,
+				 const vec<HOST_WIDE_INT> &offset_map,
 				 clause_t possible_truths,
 				 const predicate &toplev_predicate)
 {
diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h
index 3ed71046c0c..ac52b54aa36 100644
--- a/gcc/ipa-predicate.h
+++ b/gcc/ipa-predicate.h
@@ -243,7 +243,7 @@ public:
   predicate remap_after_inlining (class ipa_fn_summary *,
 		  		  class ipa_node_params *params_summary,
 			          class ipa_fn_summary *,
-				  vec<int>, vec<HOST_WIDE_INT>,
+				  const vec<int> &, const vec<HOST_WIDE_INT> &,
 				  clause_t, const predicate &);
 
   void stream_in (class lto_input_block *);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index f74d2e17b69..43f46a578c6 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -3562,7 +3562,7 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
    initializer of a constant.  */
 
 tree
-ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 			    HOST_WIDE_INT offset, bool by_ref,
 			    bool *from_global_constant)
 {
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 3d28a6e8640..d1cd42263f5 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
@@ -1092,7 +1092,7 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value,
 void ipa_analyze_node (struct cgraph_node *);
 
 /* Aggregate jump function related functions.  */
-tree ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
+tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar,
 				 HOST_WIDE_INT offset, bool by_ref,
 				 bool *from_global_constant = NULL);
 bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index 4031ce18287..42120656366 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -1672,7 +1672,7 @@ finish_cost_vectors (void)
 
 static vec<ira_loop_tree_node_t>
 ira_loop_tree_body_rev_postorder (ira_loop_tree_node_t loop_node ATTRIBUTE_UNUSED,
-				  vec<ira_loop_tree_node_t> loop_preorder)
+				  const vec<ira_loop_tree_node_t> &loop_preorder)
 {
   vec<ira_loop_tree_node_t> topsort_nodes = vNULL;
   unsigned int n_loop_preorder;
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 925402877ec..041166658d1 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -835,7 +835,7 @@ md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
    gives the iterator associated with argument I of ONAME.  */
 
 static void
-add_overload_instance (overloaded_name *oname, vec<mapping *> iterators, rtx x)
+add_overload_instance (overloaded_name *oname, const vec<mapping *> &iterators, rtx x)
 {
   /* Create the instance.  */
   overloaded_instance *instance = new overloaded_instance;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 5ed0d6dd6fa..2faf4ac4f97 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2416,9 +2416,9 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
 			       struct full_rtx_costs *);
 extern bool native_encode_rtx (machine_mode, rtx, vec<target_unit> &,
 			       unsigned int, unsigned int);
-extern rtx native_decode_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_rtx (machine_mode, const vec<target_unit> &,
 			      unsigned int);
-extern rtx native_decode_vector_rtx (machine_mode, vec<target_unit>,
+extern rtx native_decode_vector_rtx (machine_mode, const vec<target_unit> &,
 				     unsigned int, unsigned int, unsigned int);
 extern poly_uint64 subreg_lsb (const_rtx);
 extern poly_uint64 subreg_size_lsb (poly_uint64, poly_uint64, poly_uint64);
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 4727ab28920..868f1eb6c89 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -43,12 +43,12 @@ extern void sched_init_bbs (void);
 
 extern void sched_extend_luids (void);
 extern void sched_init_insn_luid (rtx_insn *);
-extern void sched_init_luids (bb_vec_t);
+extern void sched_init_luids (const bb_vec_t &);
 extern void sched_finish_luids (void);
 
 extern void sched_extend_target (void);
 
-extern void haifa_init_h_i_d (bb_vec_t);
+extern void haifa_init_h_i_d (const bb_vec_t &);
 extern void haifa_finish_h_i_d (void);
 
 /* Hooks that are common to all the schedulers.  */
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index c82101c73a4..113991ddff4 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -6742,7 +6742,7 @@ native_encode_rtx (machine_mode mode, rtx x, vec<target_unit> &bytes,
    Return the vector on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_vector_rtx (machine_mode mode, const vec<target_unit> &bytes,
 			  unsigned int first_byte, unsigned int npatterns,
 			  unsigned int nelts_per_pattern)
 {
@@ -6787,7 +6787,7 @@ native_decode_vector_rtx (machine_mode mode, vec<target_unit> bytes,
    Return the rtx on success, otherwise return NULL_RTX.  */
 
 rtx
-native_decode_rtx (machine_mode mode, vec<target_unit> bytes,
+native_decode_rtx (machine_mode mode, const vec<target_unit> &bytes,
 		   unsigned int first_byte)
 {
   if (VECTOR_MODE_P (mode))
diff --git a/gcc/tree-call-cdce.c b/gcc/tree-call-cdce.c
index 666839755d0..d9b9b4c6e84 100644
--- a/gcc/tree-call-cdce.c
+++ b/gcc/tree-call-cdce.c
@@ -761,7 +761,7 @@ get_no_error_domain (enum built_in_function fnc)
    condition are separated by NULL tree in the vector.  */
 
 static void
-gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
+gen_shrink_wrap_conditions (gcall *bi_call, const vec<gimple *> &conds,
                             unsigned int *nconds)
 {
   gcall *call;
@@ -797,7 +797,8 @@ gen_shrink_wrap_conditions (gcall *bi_call, vec<gimple *> conds,
    when it is non-null, it is called while all of the CONDS are true.  */
 
 static void
-shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
+shrink_wrap_one_built_in_call_with_conds (gcall *bi_call,
+					  const vec <gimple *> &conds,
 					  unsigned int nconds,
 					  gcall *bi_newcall = NULL)
 {
@@ -1132,7 +1133,7 @@ use_internal_fn (gcall *call)
    wrapping transformation.  */
 
 static void
-shrink_wrap_conditional_dead_built_in_calls (vec<gcall *> calls)
+shrink_wrap_conditional_dead_built_in_calls (const vec<gcall *> &calls)
 {
   unsigned i = 0;
 
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b6abd8b8de7..210ac2851a5 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -2643,7 +2643,7 @@ create_intersect_range_checks (class loop *loop, tree *cond_expr,
 
 void
 create_runtime_alias_checks (class loop *loop,
-			     vec<dr_with_seg_len_pair_t> *alias_pairs,
+			     const vec<dr_with_seg_len_pair_t> *alias_pairs,
 			     tree * cond_expr)
 {
   tree part_cond_expr;
@@ -5635,9 +5635,9 @@ compute_affine_dependence (struct data_dependence_relation *ddr,
    is small enough to be handled.  */
 
 bool
-compute_all_dependences (vec<data_reference_p> datarefs,
+compute_all_dependences (const vec<data_reference_p> &datarefs,
 			 vec<ddr_p> *dependence_relations,
-			 vec<loop_p> loop_nest,
+			 const vec<loop_p> &loop_nest,
 			 bool compute_self_and_rr)
 {
   struct data_dependence_relation *ddr;
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8001cc54f51..a0ff2a80263 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -551,9 +551,9 @@ extern struct data_dependence_relation *initialize_data_dependence_relation
 extern void compute_affine_dependence (struct data_dependence_relation *,
 				       loop_p);
 extern void compute_self_dependence (struct data_dependence_relation *);
-extern bool compute_all_dependences (vec<data_reference_p> ,
+extern bool compute_all_dependences (const vec<data_reference_p> &,
 				     vec<ddr_p> *,
-				     vec<loop_p>, bool);
+				     const vec<loop_p> &, bool);
 extern tree find_data_references_in_bb (class loop *, basic_block,
                                         vec<data_reference_p> *);
 extern unsigned int dr_alignment (innermost_loop_behavior *);
@@ -578,7 +578,8 @@ extern int data_ref_compare_tree (tree, tree);
 extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
 					   poly_uint64);
 extern void create_runtime_alias_checks (class loop *,
-					 vec<dr_with_seg_len_pair_t> *, tree*);
+					 const vec<dr_with_seg_len_pair_t> *,
+					 tree*);
 extern tree dr_direction_indicator (struct data_reference *);
 extern tree dr_zero_step_indicator (struct data_reference *);
 extern bool dr_known_forward_stride_p (struct data_reference *);
@@ -666,7 +667,7 @@ ddr_dependence_level (ddr_p ddr)
 /* Return the index of the variable VAR in the LOOP_NEST array.  */
 
 static inline int
-index_in_loop_nest (int var, vec<loop_p> loop_nest)
+index_in_loop_nest (int var, const vec<loop_p> &loop_nest)
 {
   class loop *loopi;
   int var_index;
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 345488e2a19..49e89cffa1a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -2208,7 +2208,7 @@ insert_gimplified_predicates (loop_p loop)
    mask if it was created for given SIZE and -1 otherwise.  */
 
 static int
-mask_exists (int size, vec<int> vec)
+mask_exists (int size, const vec<int> &vec)
 {
   unsigned int ix;
   int v;
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 65aa1df4aba..a984d2124f7 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -527,7 +527,8 @@ class loop_distribution
 
   /* Build the vertices of the reduced dependence graph RDG.  Return false
      if that failed.  */
-  bool create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts, loop_p loop);
+  bool create_rdg_vertices (struct graph *rdg, const vec<gimple *> &stmts,
+			    loop_p loop);
 
   /* Initialize STMTS with all the statements of LOOP.  We use topological
      order to discover all statements.  The order is important because
@@ -646,7 +647,7 @@ class loop_distribution
      statements from STMTS into separate loops.  Returns the number of
      distributed loops.  Set NB_CALLS to number of generated builtin calls.
      Set *DESTROY_P to whether LOOP needs to be destroyed.  */
-  int distribute_loop (class loop *loop, vec<gimple *> stmts,
+  int distribute_loop (class loop *loop, const vec<gimple *> &stmts,
 		       control_dependences *cd, int *nb_calls, bool *destroy_p,
 		       bool only_patterns_p);
 
@@ -699,7 +700,8 @@ bb_top_order_cmp_r (const void *x, const void *y, void *loop)
 }
 
 bool
-loop_distribution::create_rdg_vertices (struct graph *rdg, vec<gimple *> stmts,
+loop_distribution::create_rdg_vertices (struct graph *rdg,
+					const vec<gimple *> &stmts,
 					loop_p loop)
 {
   int i;
@@ -1953,7 +1955,7 @@ loop_distribution::rdg_build_partitions (struct graph *rdg,
 /* Dump to FILE the PARTITIONS.  */
 
 static void
-dump_rdg_partitions (FILE *file, vec<partition *> partitions)
+dump_rdg_partitions (FILE *file, const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -1963,10 +1965,10 @@ dump_rdg_partitions (FILE *file, vec<partition *> partitions)
 }
 
 /* Debug PARTITIONS.  */
-extern void debug_rdg_partitions (vec<partition *> );
+extern void debug_rdg_partitions (const vec<partition *> &);
 
 DEBUG_FUNCTION void
-debug_rdg_partitions (vec<partition *> partitions)
+debug_rdg_partitions (const vec<partition *> &partitions)
 {
   dump_rdg_partitions (stderr, partitions);
 }
@@ -2017,7 +2019,7 @@ number_of_rw_in_partition (struct graph *rdg, partition *partition)
 
 static bool
 partition_contains_all_rw (struct graph *rdg,
-			   vec<partition *> partitions)
+			   const vec<partition *> &partitions)
 {
   int i;
   partition *partition;
@@ -2921,7 +2923,8 @@ loop_distribution::finalize_partitions (class loop *loop,
    Set *DESTROY_P to whether LOOP needs to be destroyed.  */
 
 int
-loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts,
+loop_distribution::distribute_loop (class loop *loop,
+		 const vec<gimple *> &stmts,
 		 control_dependences *cd, int *nb_calls, bool *destroy_p,
 		 bool only_patterns_p)
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index fe1baef32a7..bb547572653 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -3713,7 +3713,7 @@ ref_conflicts_with_region (gimple_stmt_iterator gsi, ao_ref *ref,
    reduction results in REDUCTION_STORES.  */
 
 static bool
-oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_ok_1 (bitmap in_loop_bbs, const vec<basic_block> &region_bbs,
 		      reduction_info_table_type *reduction_list,
 		      bitmap reduction_stores)
 {
@@ -3828,7 +3828,8 @@ oacc_entry_exit_ok_1 (bitmap in_loop_bbs, vec<basic_block> region_bbs,
    if any changes were made.  */
 
 static bool
-oacc_entry_exit_single_gang (bitmap in_loop_bbs, vec<basic_block> region_bbs,
+oacc_entry_exit_single_gang (bitmap in_loop_bbs,
+			     const vec<basic_block> &region_bbs,
 			     bitmap reduction_stores)
 {
   tree gang_pos = NULL_TREE;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 7de47edbcb3..c778f7e87fd 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -2511,7 +2511,7 @@ sm_seq_valid_bb (class loop *loop, basic_block bb, tree vdef,
 
 static void
 hoist_memory_references (class loop *loop, bitmap mem_refs,
-			 vec<edge> exits)
+			 const vec<edge> &exits)
 {
   im_mem_ref *ref;
   unsigned  i;
@@ -2906,7 +2906,7 @@ find_refs_for_sm (class loop *loop, bitmap sm_executed, bitmap refs_to_sm)
 
 static bool
 loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED,
-		      vec<edge> exits)
+		      const vec<edge> &exits)
 {
   unsigned i;
   edge ex;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index b5add827018..3f9954c88a3 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3929,7 +3929,7 @@ wide_int_cmp (const void *p1, const void *p2)
    Lookup by binary search.  */
 
 static int
-bound_index (vec<widest_int> bounds, const widest_int &bound)
+bound_index (const vec<widest_int> &bounds, const widest_int &bound)
 {
   unsigned int end = bounds.length ();
   unsigned int begin = 0;
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index d86fe26bd07..a715cddc13d 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3100,7 +3100,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    vec<pre_expr> avail)
+			    vec<pre_expr> &avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 2dd4435b981..8498cfc7aa8 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -4486,7 +4486,7 @@ get_ops (tree var, enum tree_code code, vec<operand_entry *> *ops,
    stmts.  */
 
 static tree
-update_ops (tree var, enum tree_code code, vec<operand_entry *> ops,
+update_ops (tree var, enum tree_code code, const vec<operand_entry *> &ops,
 	    unsigned int *pidx, class loop *loop)
 {
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5033,7 +5033,7 @@ remove_visited_stmt_chain (tree var)
    cases, but it is unlikely to be worth it.  */
 
 static void
-swap_ops_for_binary_stmt (vec<operand_entry *> ops,
+swap_ops_for_binary_stmt (const vec<operand_entry *> &ops,
 			  unsigned int opindex, gimple *stmt)
 {
   operand_entry *oe1, *oe2, *oe3;
@@ -5104,7 +5104,8 @@ insert_stmt_before_use (gimple *stmt, gimple *stmt_to_insert)
 
 static tree
 rewrite_expr_tree (gimple *stmt, enum tree_code rhs_code, unsigned int opindex,
-		   vec<operand_entry *> ops, bool changed, bool next_changed)
+		   const vec<operand_entry *> &ops, bool changed,
+		   bool next_changed)
 {
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs2 = gimple_assign_rhs2 (stmt);
@@ -5326,7 +5327,7 @@ get_reassociation_width (int ops_num, enum tree_code opc,
 
 static void
 rewrite_expr_tree_parallel (gassign *stmt, int width,
-			    vec<operand_entry *> ops)
+			    const vec<operand_entry *> &ops)
 {
   enum tree_code opcode = gimple_assign_rhs_code (stmt);
   int op_num = ops.length ();
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 64e3a707f5c..3451ff1f157 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1040,9 +1040,8 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
 bool
 ao_ref_init_from_vn_reference (ao_ref *ref,
 			       alias_set_type set, alias_set_type base_set,
-			       tree type, vec<vn_reference_op_s> ops)
+			       tree type, const vec<vn_reference_op_s> &ops)
 {
-  vn_reference_op_t op;
   unsigned i;
   tree base = NULL_TREE;
   tree *op0_p = &base;
@@ -1061,7 +1060,10 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
     size = wi::to_poly_offset (size_tree);
 
   /* Lower the final access size from the outermost expression.  */
-  op = &ops[0];
+  const_vn_reference_op_t cst_op = &ops[0];
+  /* Cast away constness for the sake of the const-unsafe
+     FOR_EACH_VEC_ELT().  */
+  vn_reference_op_t op = const_cast<vn_reference_op_t>(cst_op);
   size_tree = NULL_TREE;
   if (op->opcode == COMPONENT_REF)
     size_tree = DECL_SIZE (op->op0);
@@ -1092,7 +1094,7 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
 	      && op->op0
 	      && DECL_P (TREE_OPERAND (op->op0, 0)))
 	    {
-	      vn_reference_op_t pop = &ops[i-1];
+	      const_vn_reference_op_t pop = &ops[i-1];
 	      base = TREE_OPERAND (op->op0, 0);
 	      if (known_eq (pop->off, -1))
 		{
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index 6df526c269b..96100596d2e 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -254,7 +254,7 @@ tree vn_nary_op_lookup_pieces (unsigned int, enum tree_code,
 vn_nary_op_t vn_nary_op_insert_pieces (unsigned int, enum tree_code,
 				       tree, tree *, tree, unsigned int);
 bool ao_ref_init_from_vn_reference (ao_ref *, alias_set_type, alias_set_type,
-				    tree, vec<vn_reference_op_s> );
+				    tree, const vec<vn_reference_op_s> &);
 vec<vn_reference_op_s> vn_reference_operands_for_lookup (tree);
 tree vn_reference_lookup_pieces (tree, alias_set_type, alias_set_type, tree,
 				 vec<vn_reference_op_s> ,
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 7163438e23d..e8e35362062 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3713,8 +3713,8 @@ get_constraint_for_rhs (tree t, vec<ce_s> *results)
    entries in *LHSC.  */
 
 static void
-process_all_all_constraints (vec<ce_s> lhsc,
-			     vec<ce_s> rhsc)
+process_all_all_constraints (const vec<ce_s> &lhsc,
+			     const vec<ce_s> &rhsc)
 {
   struct constraint_expr *lhsp, *rhsp;
   unsigned i, j;
@@ -3814,7 +3814,7 @@ do_structure_copy (tree lhsop, tree rhsop)
 /* Create constraints ID = { rhsc }.  */
 
 static void
-make_constraints_to (unsigned id, vec<ce_s> rhsc)
+make_constraints_to (unsigned id, const vec<ce_s> &rhsc)
 {
   struct constraint_expr *c;
   struct constraint_expr includes;
@@ -4158,7 +4158,7 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
    the LHS point to global and escaped variables.  */
 
 static void
-handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> rhsc,
+handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> &rhsc,
 		 tree fndecl)
 {
   auto_vec<ce_s> lhsc;
@@ -4609,9 +4609,10 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
       case BUILT_IN_REALLOC:
 	if (gimple_call_lhs (t))
 	  {
+	    auto_vec<ce_s> rhsc;
 	    handle_lhs_call (t, gimple_call_lhs (t),
 			     gimple_call_return_flags (t) | ERF_NOALIAS,
-			     vNULL, fndecl);
+			     rhsc, fndecl);
 	    get_constraint_for_ptr_offset (gimple_call_lhs (t),
 					   NULL_TREE, &lhsc);
 	    get_constraint_for_ptr_offset (gimple_call_arg (t, 0),
@@ -5682,7 +5683,7 @@ fieldoff_compare (const void *pa, const void *pb)
 
 /* Sort a fieldstack according to the field offset and sizes.  */
 static void
-sort_fieldstack (vec<fieldoff_s> fieldstack)
+sort_fieldstack (vec<fieldoff_s> &fieldstack)
 {
   fieldstack.qsort (fieldoff_compare);
 }
@@ -6092,7 +6093,7 @@ create_function_info_for (tree decl, const char *name, bool add_id,
    FIELDSTACK is assumed to be sorted by offset.  */
 
 static bool
-check_for_overlaps (vec<fieldoff_s> fieldstack)
+check_for_overlaps (const vec<fieldoff_s> &fieldstack)
 {
   fieldoff_s *fo = NULL;
   unsigned int i;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 579149dfd61..1e929fa002c 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -208,7 +208,7 @@ vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 static void
 vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
 {
-  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
+  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < checks.length(); ++i)
     if (checks[i] == value)
       return;
@@ -2346,7 +2346,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   if (do_versioning)
     {
       vec<stmt_vec_info> may_misalign_stmts
-        = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
+	= LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo).to_vec ();
       stmt_vec_info stmt_info;
 
       /* It can now be assumed that the data references in the statements
@@ -3360,7 +3360,8 @@ static void
 vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
 			poly_uint64 min_value)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  vec<vec_lower_bound> lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     if (operand_equal_p (lower_bounds[i].expr, expr, 0))
       {
@@ -3462,7 +3463,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
   hash_set <tree_pair_hash> compared_objects;
 
-  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
+  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).to_vec ();
   vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
     = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
   vec<vec_object_pair> &check_unequal_addrs
@@ -5335,7 +5336,7 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
    I4:  6 14 22 30  7 15 23 31.  */
 
 void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> dr_chain,
+vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
 			  unsigned int length,
 			  stmt_vec_info stmt_info,
 			  gimple_stmt_iterator *gsi,
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index 012f48bd487..9ff48fec729 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -3168,7 +3168,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
                                    tree *cond_expr,
 				   gimple_seq *cond_expr_stmt_list)
 {
-  vec<stmt_vec_info> may_misalign_stmts
+  const vec<stmt_vec_info> &may_misalign_stmts
     = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
   stmt_vec_info stmt_info;
   int mask = LOOP_VINFO_PTR_MASK (loop_vinfo);
@@ -3259,7 +3259,8 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
 static void
 vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_object_pair> pairs = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
+  const vec<vec_object_pair> &pairs
+    = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
   unsigned int i;
   vec_object_pair *pair;
   FOR_EACH_VEC_ELT (pairs, i, pair)
@@ -3278,7 +3279,8 @@ vect_create_cond_for_unequal_addrs (loop_vec_info loop_vinfo, tree *cond_expr)
 static void
 vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  const vec<vec_lower_bound> &lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     {
       tree expr = lower_bounds[i].expr;
@@ -3320,7 +3322,7 @@ vect_create_cond_for_lower_bounds (loop_vec_info loop_vinfo, tree *cond_expr)
 void
 vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
 {
-  vec<dr_with_seg_len_pair_t> comp_alias_ddrs =
+  const vec<dr_with_seg_len_pair_t> &comp_alias_ddrs =
     LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
 
   if (comp_alias_ddrs.is_empty ())
diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c
index d536494a1bd..571b29322c5 100644
--- a/gcc/tree-vect-slp-patterns.c
+++ b/gcc/tree-vect-slp-patterns.c
@@ -746,7 +746,7 @@ vect_match_call_complex_mla (slp_tree node, unsigned child,
    of the negate node.  */
 
 static inline bool
-vect_normalize_conj_loc (vec<slp_tree> args, bool *neg_first_p = NULL)
+vect_normalize_conj_loc (vec<slp_tree> &args, bool *neg_first_p = NULL)
 {
   gcc_assert (args.length () == 2);
   bool neg_found = false;
@@ -790,7 +790,8 @@ is_eq_or_top (complex_perm_kinds_t perm, complex_perm_kinds_t kind)
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> left_op, vec<slp_tree> right_op,
+			      const vec<slp_tree> &left_op,
+			      const vec<slp_tree> &right_op,
 			     bool neg_first, bool *conj_first_operand,
 			     bool fms)
 {
@@ -862,7 +863,8 @@ vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
 
 static inline bool
 vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache,
-			     vec<slp_tree> op, complex_perm_kinds_t permKind)
+			      const vec<slp_tree> &op,
+			      complex_perm_kinds_t permKind)
 {
   /* The left node is the more common case, test it first.  */
   if (!is_eq_or_top (linear_loads_p (perm_cache, op[0]), permKind))
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 227d6aa3ee8..5a4b6fe8b0c 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -3316,7 +3316,8 @@ vect_analyze_slp_instance (vec_info *vinfo,
   else if (kind == slp_inst_kind_reduc_group)
     {
       /* Collect reduction statements.  */
-      vec<stmt_vec_info> reductions = as_a <loop_vec_info> (vinfo)->reductions;
+      const vec<stmt_vec_info> &reductions
+	= as_a <loop_vec_info> (vinfo)->reductions;
       scalar_stmts.create (reductions.length ());
       for (i = 0; reductions.iterate (i, &next_info); i++)
 	if (STMT_VINFO_RELEVANT_P (next_info)
@@ -4047,7 +4048,8 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
 {
   unsigned int i;
   poly_uint64 unrolling_factor = 1;
-  vec<slp_instance> slp_instances = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
+  const vec<slp_instance> &slp_instances
+    = LOOP_VINFO_SLP_INSTANCES (loop_vinfo);
   slp_instance instance;
   int decided_to_slp = 0;
 
@@ -5814,7 +5816,7 @@ vect_slp_region (vec<basic_block> bbs, vec<data_reference_p> datarefs,
    true if anything in the basic-block was vectorized.  */
 
 static bool
-vect_slp_bbs (vec<basic_block> bbs)
+vect_slp_bbs (const vec<basic_block> &bbs)
 {
   vec<data_reference_p> datarefs = vNULL;
   auto_vec<int> dataref_groups;
@@ -5959,7 +5961,7 @@ vect_slp_function (function *fun)
 
 void
 duplicate_and_interleave (vec_info *vinfo, gimple_seq *seq, tree vector_type,
-			  vec<tree> elts, unsigned int nresults,
+			  const vec<tree> &elts, unsigned int nresults,
 			  vec<tree> &results)
 {
   unsigned int nelts = elts.length ();
@@ -6315,7 +6317,7 @@ vect_get_slp_defs (vec_info *,
 
 bool
 vect_transform_slp_perm_load (vec_info *vinfo,
-			      slp_tree node, vec<tree> dr_chain,
+			      slp_tree node, const vec<tree> &dr_chain,
 			      gimple_stmt_iterator *gsi, poly_uint64 vf,
 			      bool analyze_only, unsigned *n_perms,
 			      unsigned int *n_loads, bool dce_chain)
@@ -7329,7 +7331,7 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance,
 /* Generate vector code for SLP_INSTANCES in the loop/basic block.  */
 
 void
-vect_schedule_slp (vec_info *vinfo, vec<slp_instance> slp_instances)
+vect_schedule_slp (vec_info *vinfo, const vec<slp_instance> &slp_instances)
 {
   slp_instance instance;
   unsigned int i;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 4ee11b2041a..7d99199b968 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4437,7 +4437,7 @@ static void
 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
 				       int multi_step_cvt,
 				       stmt_vec_info stmt_info,
-				       vec<tree> vec_dsts,
+				       vec<tree> &vec_dsts,
 				       gimple_stmt_iterator *gsi,
 				       slp_tree slp_node, enum tree_code code)
 {
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index fa28336d429..a707f6e243c 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1927,8 +1927,8 @@ extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT);
 extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
 extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
 extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
-extern void vect_permute_store_chain (vec_info *,
-				      vec<tree> ,unsigned int, stmt_vec_info,
+extern void vect_permute_store_chain (vec_info *, vec<tree> &,
+				      unsigned int, stmt_vec_info,
 				      gimple_stmt_iterator *, vec<tree> *);
 extern tree vect_setup_realignment (vec_info *,
 				    stmt_vec_info, gimple_stmt_iterator *,
@@ -2009,12 +2009,12 @@ extern tree cse_and_gimplify_to_preheader (loop_vec_info, tree);
 extern void vect_slp_init (void);
 extern void vect_slp_fini (void);
 extern void vect_free_slp_instance (slp_instance);
-extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, vec<tree>,
+extern bool vect_transform_slp_perm_load (vec_info *, slp_tree, const vec<tree> &,
 					  gimple_stmt_iterator *, poly_uint64,
 					  bool, unsigned *,
 					  unsigned * = nullptr, bool = false);
 extern bool vect_slp_analyze_operations (vec_info *);
-extern void vect_schedule_slp (vec_info *, vec<slp_instance>);
+extern void vect_schedule_slp (vec_info *, const vec<slp_instance> &);
 extern opt_result vect_analyze_slp (vec_info *, unsigned);
 extern bool vect_make_slp_decision (loop_vec_info);
 extern void vect_detect_hybrid_slp (loop_vec_info);
@@ -2032,7 +2032,7 @@ extern bool can_duplicate_and_interleave_p (vec_info *, unsigned int, tree,
 					    unsigned int * = NULL,
 					    tree * = NULL, tree * = NULL);
 extern void duplicate_and_interleave (vec_info *, gimple_seq *, tree,
-				      vec<tree>, unsigned int, vec<tree> &);
+				      const vec<tree> &, unsigned int, vec<tree> &);
 extern int vect_get_place_in_interleaving_chain (stmt_vec_info, stmt_vec_info);
 extern bool vect_update_shared_vectype (stmt_vec_info, tree);
 extern slp_tree vect_create_new_slp_node (unsigned, tree_code);
diff --git a/gcc/tree.c b/gcc/tree.c
index 1aa6e557a04..bead1ac134c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2047,7 +2047,7 @@ make_vector (unsigned log2_npatterns,
    are extracted from V, a vector of CONSTRUCTOR_ELT.  */
 
 tree
-build_vector_from_ctor (tree type, vec<constructor_elt, va_gc> *v)
+build_vector_from_ctor (tree type, const vec<constructor_elt, va_gc> *v)
 {
   if (vec_safe_length (v) == 0)
     return build_zero_cst (type);
@@ -14428,7 +14428,7 @@ test_labels ()
    are given by VALS.  */
 
 static tree
-build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
+build_vector (tree type, const vec<tree> &vals MEM_STAT_DECL)
 {
   gcc_assert (known_eq (vals.length (), TYPE_VECTOR_SUBPARTS (type)));
   tree_vector_builder builder (type, vals.length (), 1);
@@ -14439,7 +14439,7 @@ build_vector (tree type, vec<tree> vals MEM_STAT_DECL)
 /* Check that VECTOR_CST ACTUAL contains the elements in EXPECTED.  */
 
 static void
-check_vector_cst (vec<tree> expected, tree actual)
+check_vector_cst (const vec<tree> &expected, tree actual)
 {
   ASSERT_KNOWN_EQ (expected.length (),
 		   TYPE_VECTOR_SUBPARTS (TREE_TYPE (actual)));
@@ -14452,7 +14452,7 @@ check_vector_cst (vec<tree> expected, tree actual)
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_duplicate (vec<tree> expected, tree actual,
+check_vector_cst_duplicate (const vec<tree> &expected, tree actual,
 			    unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14468,7 +14468,7 @@ check_vector_cst_duplicate (vec<tree> expected, tree actual,
    EXPECTED.  */
 
 static void
-check_vector_cst_fill (vec<tree> expected, tree actual,
+check_vector_cst_fill (const vec<tree> &expected, tree actual,
 		       unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
@@ -14483,7 +14483,7 @@ check_vector_cst_fill (vec<tree> expected, tree actual,
    and that its elements match EXPECTED.  */
 
 static void
-check_vector_cst_stepped (vec<tree> expected, tree actual,
+check_vector_cst_stepped (const vec<tree> &expected, tree actual,
 			  unsigned int npatterns)
 {
   ASSERT_EQ (npatterns, VECTOR_CST_NPATTERNS (actual));
diff --git a/gcc/tree.h b/gcc/tree.h
index 060ddee09dd..7043ae2cddc 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4474,7 +4474,7 @@ extern tree build_int_cst (tree, poly_int64);
 extern tree build_int_cstu (tree type, poly_uint64);
 extern tree build_int_cst_type (tree, poly_int64);
 extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO);
-extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
+extern tree build_vector_from_ctor (tree, const vec<constructor_elt, va_gc> *);
 extern tree build_vector_from_val (tree, tree);
 extern tree build_uniform_cst (tree, tree);
 extern tree build_vec_series (tree, tree, tree);
diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..6d767cc12c1 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -38,16 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #endif
 
-/* vNULL is an empty type with a template cast operation that returns
-   a zero-initialized vec<T, A, L> instance.  Use this when you want
-   to assign nil values to new vec instances or pass a nil vector as
-   a function call argument.
-
-   We use this technique because vec<T, A, L> must be PODs (they are
-   stored in unions and passed in vararg functions), this means that
-   they cannot have ctors/dtors.  */
-vnull vNULL;
-
 /* Vector memory usage.  */
 class vec_usage: public mem_usage
 {
@@ -282,6 +272,42 @@ safe_push_range (vec <int>&v, int start, int limit)
     v.safe_push (i);
 }
 
+/* Verify forms of initialization.  */
+
+static void
+test_init ()
+{
+  {
+    vec<int> v1{ };
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 = vec<int>();
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 = v1;
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 (vNULL);
+    ASSERT_EQ (0, v1.length ());
+    v1.safe_push (1);
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (1, v1.length ());
+    v2.safe_push (1);
+
+    ASSERT_EQ (2, v1.length ());
+    ASSERT_EQ (2, v2.length ());
+    v1.release ();
+  }
+}
+
 /* Verify that vec::quick_push works correctly.  */
 
 static void
@@ -547,6 +573,7 @@ test_auto_delete_vec ()
 void
 vec_c_tests ()
 {
+  test_init ();
   test_quick_push ();
   test_safe_push ();
   test_truncate ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..d005c908bf4 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -541,18 +541,16 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
     ::new (static_cast<void*>(dst)) T (*src);
 }
 
-/* Type to provide NULL values for vec<T, A, L>.  This is used to
-   provide nil initializers for vec instances.  Since vec must be
-   a POD, we cannot have proper ctor/dtor for it.  To initialize
-   a vec instance, you can assign it the value vNULL.  This isn't
-   needed for file-scope and function-local static vectors, which
-   are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
-extern vnull vNULL;
+/* Type to provide zero-initialized values for vec<T, A, L>.  This is
+   used to  provide nil initializers for vec instances.  Since vec must
+   be a trivially copyable type that can be copied by memcpy and zeroed
+   out by memset, it must have defaulted default and copy ctor and copy
+   assignment.  To initialize a vec either use value initialization
+   (e.g., vec() or vec v{ };) or assign it the value vNULL.  This isn't
+   needed for file-scope and function-local static vectors, which are
+   zero-initialized by default.  */
+struct vnull { };
+constexpr vnull vNULL{ };
 
 
 /* Embeddable vector.  These vectors are suitable to be embedded
@@ -1431,10 +1429,34 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
    As long as we use C++03, we cannot have constructors nor
    destructors in classes that are stored in unions.  */
 
+template<typename T, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  /* Default ctors to ensure triviality.  Use value-initialization
+     (e.g., vec() or vec v{ };) or vNULL to create a zero-initialized
+     instance.  */
+  vec () = default;
+  vec (const vec &) = default;
+  /* Initialization from the generic vNULL.  */
+  vec (vnull): m_vec () { }
+  /* Same as default ctor: vec storage must be released manually.  */
+  ~vec () = default;
+
+  /* Defaulted same as copy ctor.  */
+  vec& operator= (const vec &) = default;
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1544,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1571,13 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1631,13 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // 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 ().
@@ -1781,7 +1817,7 @@ template<typename T>
 inline vec<T, va_heap, vl_ptr>
 vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
 {
-  vec<T, va_heap, vl_ptr> new_vec = vNULL;
+  vec<T, va_heap, vl_ptr> new_vec{ };
   if (length ())
     new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT);
   return new_vec;

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-14  3:39                                           ` Jason Merrill
  2021-07-14 10:47                                             ` Jonathan Wakely
@ 2021-07-14 14:46                                             ` Martin Sebor
  2021-07-14 16:23                                               ` Jason Merrill
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-07-14 14:46 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/13/21 9:39 PM, Jason Merrill wrote:
> On 7/13/21 4:02 PM, Martin Sebor wrote:
>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>> vec.h changes - I don't feel competent to assess all effects of the 
>>>>> change.
>>>>
>>>> They look OK to me except for:
>>>>
>>>> -extern vnull vNULL;
>>>> +static constexpr vnull vNULL{ };
>>>>
>>>> Making vNULL have static linkage can make it an ODR violation to use
>>>> vNULL in templates and inline functions, because different
>>>> instantiations will refer to a different "vNULL" in each translation
>>>> unit.
>>>
>>> The ODR says this is OK because it's a literal constant with the same 
>>> value (6.2/12.2.1).
>>>
>>> But it would be better without the explicit 'static'; then in C++17 
>>> it's implicitly inline instead of static.
>>
>> I'll remove the static.
>>
>>>
>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>> blurring of the object/pointer boundary that is also dependent on vec 
>>> being a thin wrapper around a pointer.  In almost all cases it can be 
>>> replaced with {}; one exception is == comparison, where it seems to 
>>> be testing that the embedded pointer is null, which is a weird thing 
>>> to want to test.
>>
>> The one use case I know of for vNULL where I can't think of
>> an equally good substitute is in passing a vec as an argument by
>> value.  The only way to do that that I can think of is to name
>> the full vec type (i.e., the specialization) which is more typing
>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>> miss this trick if it were to be removed but others might feel
>> differently.
> 
> In C++11, it can be replaced by {} in that context as well.

Cool.  I thought I'd tried { } here but I guess not.

> 
>> If not, I'm all for getting rid of vNULL but with over 350 uses
>> of it left, unless there's some clever trick to make the removal
>> (mostly) effortless and seamless, I'd much rather do it independently
>> of this initial change. I also don't know if I can commit to making
>> all this cleanup.
> 
> I already have a patch to replace all but one use of vNULL, but I'll 
> hold off with it until after your patch.

So what's the next step?  The patch only removes a few uses of vNULL
but doesn't add any.  Is it good to go as is (without the static and
with the additional const changes Richard suggested)?  This patch is
attached to my reply to Richard:
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html

Martin

> 
>>> Somewhat relatedly, use of vec<T> variables or fields seems almost 
>>> always a mistake, as they need explicit .release() that could be 
>>> automatic with auto_vec, and is easy to forget.  For instance, the 
>>> recursive call in get_all_loop_exits returns a vec that is never 
>>> released.  And I see a couple of leaks in the C++ front end as well.
>>
>> I agree.  The challenge I ran into with changing vec fields is with
>> code that uses the vec member as a reference to auto_vec.  This is
>> the case in gcc/ipa-prop.h, for instance.  Those instances could
>> be changed to auto_vec references or pointers but again it's a more
>> intrusive change than the simple replacements I was planning to make
>> in this first iteration.
>>
>> So in summary, I agree with the changes you suggest.  Given their
>> scope I'd prefer not to make them in the same patch, and rather make
>> them at some point in the future when I or someone else has the time
>> and energy.  I'm running out.
> 
> Oh, absolutely.
> 
> Jason
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-14 14:46                                             ` Martin Sebor
@ 2021-07-14 16:23                                               ` Jason Merrill
  2021-07-20 18:34                                                 ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-07-14 16:23 UTC (permalink / raw)
  To: Martin Sebor, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/14/21 10:46 AM, Martin Sebor wrote:
> On 7/13/21 9:39 PM, Jason Merrill wrote:
>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>> vec.h changes - I don't feel competent to assess all effects of 
>>>>>> the change.
>>>>>
>>>>> They look OK to me except for:
>>>>>
>>>>> -extern vnull vNULL;
>>>>> +static constexpr vnull vNULL{ };
>>>>>
>>>>> Making vNULL have static linkage can make it an ODR violation to use
>>>>> vNULL in templates and inline functions, because different
>>>>> instantiations will refer to a different "vNULL" in each translation
>>>>> unit.
>>>>
>>>> The ODR says this is OK because it's a literal constant with the 
>>>> same value (6.2/12.2.1).
>>>>
>>>> But it would be better without the explicit 'static'; then in C++17 
>>>> it's implicitly inline instead of static.
>>>
>>> I'll remove the static.
>>>
>>>>
>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>> blurring of the object/pointer boundary that is also dependent on 
>>>> vec being a thin wrapper around a pointer.  In almost all cases it 
>>>> can be replaced with {}; one exception is == comparison, where it 
>>>> seems to be testing that the embedded pointer is null, which is a 
>>>> weird thing to want to test.
>>>
>>> The one use case I know of for vNULL where I can't think of
>>> an equally good substitute is in passing a vec as an argument by
>>> value.  The only way to do that that I can think of is to name
>>> the full vec type (i.e., the specialization) which is more typing
>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>> miss this trick if it were to be removed but others might feel
>>> differently.
>>
>> In C++11, it can be replaced by {} in that context as well.
> 
> Cool.  I thought I'd tried { } here but I guess not.
> 
>>
>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>> of it left, unless there's some clever trick to make the removal
>>> (mostly) effortless and seamless, I'd much rather do it independently
>>> of this initial change. I also don't know if I can commit to making
>>> all this cleanup.
>>
>> I already have a patch to replace all but one use of vNULL, but I'll 
>> hold off with it until after your patch.
> 
> So what's the next step?  The patch only removes a few uses of vNULL
> but doesn't add any.  Is it good to go as is (without the static and
> with the additional const changes Richard suggested)?  This patch is
> attached to my reply to Richard:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html

As Richard wrote:

> The pieces where you change vec<> passing to const vec<>& and the few
> where you change vec<> * to const vec<> * are OK - this should make the
> rest a smaller piece to review.

Please go ahead and apply those changes and send a new patch with the 
remainder of the changes.

A few other comments:

> -				       omp_declare_simd_clauses);
> +				       *omp_declare_simd_clauses);

Instead of doing this indirection in all of the callers, let's change 
c_finish_omp_declare_simd to take a pointer as well, and do the 
indirection in initializing a reference variable at the top of the function.

> +    sched_init_luids (bbs.to_vec ());
> +    haifa_init_h_i_d (bbs.to_vec ());

Why are these to_vec changes needed when you are also changing the 
functions to take const&?

> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();

Why not use a reference here and in other similar spots?

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-14 16:23                                               ` Jason Merrill
@ 2021-07-20 18:34                                                 ` Martin Sebor
  2021-07-20 20:08                                                   ` Jason Merrill
  2021-07-27 18:56                                                   ` Martin Sebor
  0 siblings, 2 replies; 59+ messages in thread
From: Martin Sebor @ 2021-07-20 18:34 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4264 bytes --]

On 7/14/21 10:23 AM, Jason Merrill wrote:
> On 7/14/21 10:46 AM, Martin Sebor wrote:
>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>>> vec.h changes - I don't feel competent to assess all effects of 
>>>>>>> the change.
>>>>>>
>>>>>> They look OK to me except for:
>>>>>>
>>>>>> -extern vnull vNULL;
>>>>>> +static constexpr vnull vNULL{ };
>>>>>>
>>>>>> Making vNULL have static linkage can make it an ODR violation to use
>>>>>> vNULL in templates and inline functions, because different
>>>>>> instantiations will refer to a different "vNULL" in each translation
>>>>>> unit.
>>>>>
>>>>> The ODR says this is OK because it's a literal constant with the 
>>>>> same value (6.2/12.2.1).
>>>>>
>>>>> But it would be better without the explicit 'static'; then in C++17 
>>>>> it's implicitly inline instead of static.
>>>>
>>>> I'll remove the static.
>>>>
>>>>>
>>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>>> blurring of the object/pointer boundary that is also dependent on 
>>>>> vec being a thin wrapper around a pointer.  In almost all cases it 
>>>>> can be replaced with {}; one exception is == comparison, where it 
>>>>> seems to be testing that the embedded pointer is null, which is a 
>>>>> weird thing to want to test.
>>>>
>>>> The one use case I know of for vNULL where I can't think of
>>>> an equally good substitute is in passing a vec as an argument by
>>>> value.  The only way to do that that I can think of is to name
>>>> the full vec type (i.e., the specialization) which is more typing
>>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>>> miss this trick if it were to be removed but others might feel
>>>> differently.
>>>
>>> In C++11, it can be replaced by {} in that context as well.
>>
>> Cool.  I thought I'd tried { } here but I guess not.
>>
>>>
>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>>> of it left, unless there's some clever trick to make the removal
>>>> (mostly) effortless and seamless, I'd much rather do it independently
>>>> of this initial change. I also don't know if I can commit to making
>>>> all this cleanup.
>>>
>>> I already have a patch to replace all but one use of vNULL, but I'll 
>>> hold off with it until after your patch.
>>
>> So what's the next step?  The patch only removes a few uses of vNULL
>> but doesn't add any.  Is it good to go as is (without the static and
>> with the additional const changes Richard suggested)?  This patch is
>> attached to my reply to Richard:
>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
> 
> As Richard wrote:
> 
>> The pieces where you change vec<> passing to const vec<>& and the few
>> where you change vec<> * to const vec<> * are OK - this should make the
>> rest a smaller piece to review.
> 
> Please go ahead and apply those changes and send a new patch with the 
> remainder of the changes.

I have just pushed r12-2418:
https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html

> 
> A few other comments:
> 
>> -                       omp_declare_simd_clauses);
>> +                       *omp_declare_simd_clauses);
> 
> Instead of doing this indirection in all of the callers, let's change 
> c_finish_omp_declare_simd to take a pointer as well, and do the 
> indirection in initializing a reference variable at the top of the 
> function.

Okay.

> 
>> +    sched_init_luids (bbs.to_vec ());
>> +    haifa_init_h_i_d (bbs.to_vec ());
> 
> Why are these to_vec changes needed when you are also changing the 
> functions to take const&?

Calling to_vec() here isn't necessary so I've removed it.

> 
>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
> 
> Why not use a reference here and in other similar spots?

Sure, that works too.

Attached is what's left of the original changes now that r12-2418
has been applied.

Martin

[-- Attachment #2: gcc-auto_vec-no-convert.diff --]
[-- Type: text/x-patch, Size: 22676 bytes --]

Disable implicit conversion from auto_vec to vec.

gcc/c/ChangeLog:

	* c-parser.c (c_finish_omp_declare_simd): Adjust to vec change.
	(c_parser_omp_declare_simd): Same.
	* c-tree.h (c_build_function_call_vec): Same.
	* c-typeck.c (c_build_function_call_vec): Same.

gcc/ChangeLog:

	* dominance.c (prune_bbs_to_update_dominators): Adjust to vec change.
	(iterate_fix_dominators): Same.
	* dominance.h (iterate_fix_dominators): Same.
	* ipa-prop.h:
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-vect-data-refs.c (vect_check_nonzero_value): Same.
	(vect_enhance_data_refs_alignment): Same.
	(vect_check_lower_bound): Same.
	(vect_prune_runtime_alias_test_list): Same.
	(vect_permute_store_chain): Same.
	* tree-vect-slp-patterns.c (vect_normalize_conj_loc): Same.
	* tree-vect-stmts.c (vect_create_vectorized_demotion_stmts): Same.
	* tree-vectorizer.h (vect_permute_store_chain): Same.
	* vec.c (test_init): New.
	(vec_c_tests): Call test_init.
	* vec.h (struct vnull): Simplify.
	(auto_vec::to_vec): New member function.
	(vl_ptr>::copy): Use value initialization.

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 9a56e0c04c6..fa3c9fa3a1b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *, vec<c_token>,
+					   bool, bool, tree * = NULL,
+					   vec<c_token> * = NULL,
 					   bool have_attrs = false,
 					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
@@ -1774,13 +1775,12 @@ c_parser_external_declaration (c_parser *parser)
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				     NULL, vNULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> *);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -1890,11 +1890,15 @@ static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration,
-			       vec<c_token> omp_declare_simd_clauses,
-			       bool have_attrs, tree attrs,
-			       struct oacc_routine_data *oacc_routine_data,
-			       bool *fallthru_attr_p)
+			       tree *objc_foreach_object_declaration
+			       /* = NULL */,
+			       vec<c_token> *omp_declare_simd_clauses
+			       /* = NULL */,
+			       bool have_attrs /* = false */,
+			       tree attrs /* = NULL_TREE */,
+			       struct oacc_routine_data *oacc_routine_data
+			       /* = NULL */,
+			       bool *fallthru_attr_p /* = NULL */)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -2150,7 +2154,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses)
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
 				       omp_declare_simd_clauses);
 	  if (oacc_routine_data)
@@ -2250,7 +2254,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		}
@@ -2262,7 +2266,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		  init_loc = c_parser_peek_token (parser)->location;
@@ -2342,7 +2346,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      warn_parm_array_mismatch (lastloc, d, parms);
 		    }
 		}
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses)
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2496,9 +2500,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL, vNULL);
+				       true, false);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses)
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
 				   omp_declare_simd_clauses);
       if (oacc_routine_data)
@@ -5699,7 +5703,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
-					 vNULL, have_std_attrs, std_attrs,
+					 NULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
 
 	  if (last_stmt && !fallthru_attr_p)
@@ -5731,7 +5735,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, vNULL);
+					     true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -6782,7 +6786,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression, vNULL);
+					 &object_expression);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -6813,7 +6817,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression, vNULL);
+					     true, &object_expression);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -11277,7 +11281,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL, vNULL);
+					   false, true);
 	  break;
 	}
     }
@@ -17273,12 +17277,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, false, NULL, &data);
+					 NULL, NULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, false, NULL, &data);
+				       NULL, NULL, false, NULL, &data);
     }
 }
 
@@ -18385,8 +18389,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
 	  this_pre_body = push_stmt_list ();
 	  c_in_omp_for = true;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, vNULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true);
 	  c_in_omp_for = false;
 	  if (this_pre_body)
 	    {
@@ -20327,12 +20330,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, &clauses);
       break;
     case pragma_struct:
     case pragma_param:
@@ -20353,7 +20356,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, &clauses);
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20362,7 +20365,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20843,8 +20846,10 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> *pclauses)
 {
+  vec<c_token> &clauses = *pclauses;
+
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that
      c_finish_omp_declare_simd has already processed the tokens.  */
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 2fe220acf84..d1cd42263f5 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index d2a7395dd8f..ebe95cc6c73 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3107,7 +3107,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    vec<pre_expr> avail)
+			    vec<pre_expr> &avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 6995efba899..b88e744e4a0 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -212,7 +212,7 @@ vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 static void
 vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
 {
-  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
+  vec<tree> &checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
   for (unsigned int i = 0; i < checks.length(); ++i)
     if (checks[i] == value)
       return;
@@ -2349,8 +2349,8 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
 
   if (do_versioning)
     {
-      vec<stmt_vec_info> may_misalign_stmts
-        = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
+      vec<stmt_vec_info> &may_misalign_stmts
+	= LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
       stmt_vec_info stmt_info;
 
       /* It can now be assumed that the data references in the statements
@@ -3364,7 +3364,8 @@ static void
 vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
 			poly_uint64 min_value)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  vec<vec_lower_bound> lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     if (operand_equal_p (lower_bounds[i].expr, expr, 0))
       {
@@ -3466,7 +3467,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
   hash_set <tree_pair_hash> compared_objects;
 
-  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
+  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).to_vec ();
   vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
     = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
   vec<vec_object_pair> &check_unequal_addrs
@@ -5339,7 +5340,7 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
    I4:  6 14 22 30  7 15 23 31.  */
 
 void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> dr_chain,
+vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
 			  unsigned int length,
 			  stmt_vec_info stmt_info,
 			  gimple_stmt_iterator *gsi,
diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c
index ad209deca79..b8d09b7832e 100644
--- a/gcc/tree-vect-slp-patterns.c
+++ b/gcc/tree-vect-slp-patterns.c
@@ -746,7 +746,7 @@ vect_match_call_complex_mla (slp_tree node, unsigned child,
    of the negate node.  */
 
 static inline bool
-vect_normalize_conj_loc (vec<slp_tree> args, bool *neg_first_p = NULL)
+vect_normalize_conj_loc (vec<slp_tree> &args, bool *neg_first_p = NULL)
 {
   gcc_assert (args.length () == 2);
   bool neg_found = false;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index d71552296bb..d88f65f3550 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4462,7 +4462,7 @@ static void
 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
 				       int multi_step_cvt,
 				       stmt_vec_info stmt_info,
-				       vec<tree> vec_dsts,
+				       vec<tree> &vec_dsts,
 				       gimple_stmt_iterator *gsi,
 				       slp_tree slp_node, enum tree_code code)
 {
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index deb22477e28..45b61fa4793 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1990,8 +1990,8 @@ extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT);
 extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
 extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
 extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
-extern void vect_permute_store_chain (vec_info *,
-				      vec<tree> ,unsigned int, stmt_vec_info,
+extern void vect_permute_store_chain (vec_info *, vec<tree> &,
+				      unsigned int, stmt_vec_info,
 				      gimple_stmt_iterator *, vec<tree> *);
 extern tree vect_setup_realignment (vec_info *,
 				    stmt_vec_info, gimple_stmt_iterator *,
diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..6d767cc12c1 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -38,16 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #endif
 
-/* vNULL is an empty type with a template cast operation that returns
-   a zero-initialized vec<T, A, L> instance.  Use this when you want
-   to assign nil values to new vec instances or pass a nil vector as
-   a function call argument.
-
-   We use this technique because vec<T, A, L> must be PODs (they are
-   stored in unions and passed in vararg functions), this means that
-   they cannot have ctors/dtors.  */
-vnull vNULL;
-
 /* Vector memory usage.  */
 class vec_usage: public mem_usage
 {
@@ -282,6 +272,42 @@ safe_push_range (vec <int>&v, int start, int limit)
     v.safe_push (i);
 }
 
+/* Verify forms of initialization.  */
+
+static void
+test_init ()
+{
+  {
+    vec<int> v1{ };
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 = vec<int>();
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 = v1;
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 (vNULL);
+    ASSERT_EQ (0, v1.length ());
+    v1.safe_push (1);
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (1, v1.length ());
+    v2.safe_push (1);
+
+    ASSERT_EQ (2, v1.length ());
+    ASSERT_EQ (2, v2.length ());
+    v1.release ();
+  }
+}
+
 /* Verify that vec::quick_push works correctly.  */
 
 static void
@@ -547,6 +573,7 @@ test_auto_delete_vec ()
 void
 vec_c_tests ()
 {
+  test_init ();
   test_quick_push ();
   test_safe_push ();
   test_truncate ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..d005c908bf4 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -541,18 +541,16 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
     ::new (static_cast<void*>(dst)) T (*src);
 }
 
-/* Type to provide NULL values for vec<T, A, L>.  This is used to
-   provide nil initializers for vec instances.  Since vec must be
-   a POD, we cannot have proper ctor/dtor for it.  To initialize
-   a vec instance, you can assign it the value vNULL.  This isn't
-   needed for file-scope and function-local static vectors, which
-   are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
-extern vnull vNULL;
+/* Type to provide zero-initialized values for vec<T, A, L>.  This is
+   used to  provide nil initializers for vec instances.  Since vec must
+   be a trivially copyable type that can be copied by memcpy and zeroed
+   out by memset, it must have defaulted default and copy ctor and copy
+   assignment.  To initialize a vec either use value initialization
+   (e.g., vec() or vec v{ };) or assign it the value vNULL.  This isn't
+   needed for file-scope and function-local static vectors, which are
+   zero-initialized by default.  */
+struct vnull { };
+constexpr vnull vNULL{ };
 
 
 /* Embeddable vector.  These vectors are suitable to be embedded
@@ -1431,10 +1429,34 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
    As long as we use C++03, we cannot have constructors nor
    destructors in classes that are stored in unions.  */
 
+template<typename T, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  /* Default ctors to ensure triviality.  Use value-initialization
+     (e.g., vec() or vec v{ };) or vNULL to create a zero-initialized
+     instance.  */
+  vec () = default;
+  vec (const vec &) = default;
+  /* Initialization from the generic vNULL.  */
+  vec (vnull): m_vec () { }
+  /* Same as default ctor: vec storage must be released manually.  */
+  ~vec () = default;
+
+  /* Defaulted same as copy ctor.  */
+  vec& operator= (const vec &) = default;
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1544,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1571,13 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1631,13 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.  */
+  vec<T, va_heap> to_vec () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // 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 ().
@@ -1781,7 +1817,7 @@ template<typename T>
 inline vec<T, va_heap, vl_ptr>
 vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
 {
-  vec<T, va_heap, vl_ptr> new_vec = vNULL;
+  vec<T, va_heap, vl_ptr> new_vec{ };
   if (length ())
     new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT);
   return new_vec;

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-20 18:34                                                 ` Martin Sebor
@ 2021-07-20 20:08                                                   ` Jason Merrill
  2021-07-20 21:52                                                     ` Martin Sebor
  2021-07-27 18:56                                                   ` Martin Sebor
  1 sibling, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-07-20 20:08 UTC (permalink / raw)
  To: Martin Sebor, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/20/21 2:34 PM, Martin Sebor wrote:
> On 7/14/21 10:23 AM, Jason Merrill wrote:
>> On 7/14/21 10:46 AM, Martin Sebor wrote:
>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>>>> vec.h changes - I don't feel competent to assess all effects of 
>>>>>>>> the change.
>>>>>>>
>>>>>>> They look OK to me except for:
>>>>>>>
>>>>>>> -extern vnull vNULL;
>>>>>>> +static constexpr vnull vNULL{ };
>>>>>>>
>>>>>>> Making vNULL have static linkage can make it an ODR violation to use
>>>>>>> vNULL in templates and inline functions, because different
>>>>>>> instantiations will refer to a different "vNULL" in each translation
>>>>>>> unit.
>>>>>>
>>>>>> The ODR says this is OK because it's a literal constant with the 
>>>>>> same value (6.2/12.2.1).
>>>>>>
>>>>>> But it would be better without the explicit 'static'; then in 
>>>>>> C++17 it's implicitly inline instead of static.
>>>>>
>>>>> I'll remove the static.
>>>>>
>>>>>>
>>>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>>>> blurring of the object/pointer boundary that is also dependent on 
>>>>>> vec being a thin wrapper around a pointer.  In almost all cases it 
>>>>>> can be replaced with {}; one exception is == comparison, where it 
>>>>>> seems to be testing that the embedded pointer is null, which is a 
>>>>>> weird thing to want to test.
>>>>>
>>>>> The one use case I know of for vNULL where I can't think of
>>>>> an equally good substitute is in passing a vec as an argument by
>>>>> value.  The only way to do that that I can think of is to name
>>>>> the full vec type (i.e., the specialization) which is more typing
>>>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>>>> miss this trick if it were to be removed but others might feel
>>>>> differently.
>>>>
>>>> In C++11, it can be replaced by {} in that context as well.
>>>
>>> Cool.  I thought I'd tried { } here but I guess not.
>>>
>>>>
>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>>>> of it left, unless there's some clever trick to make the removal
>>>>> (mostly) effortless and seamless, I'd much rather do it independently
>>>>> of this initial change. I also don't know if I can commit to making
>>>>> all this cleanup.
>>>>
>>>> I already have a patch to replace all but one use of vNULL, but I'll 
>>>> hold off with it until after your patch.
>>>
>>> So what's the next step?  The patch only removes a few uses of vNULL
>>> but doesn't add any.  Is it good to go as is (without the static and
>>> with the additional const changes Richard suggested)?  This patch is
>>> attached to my reply to Richard:
>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
>>
>> As Richard wrote:
>>
>>> The pieces where you change vec<> passing to const vec<>& and the few
>>> where you change vec<> * to const vec<> * are OK - this should make the
>>> rest a smaller piece to review.
>>
>> Please go ahead and apply those changes and send a new patch with the 
>> remainder of the changes.
> 
> I have just pushed r12-2418:
> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
> 
>>
>> A few other comments:
>>
>>> -                       omp_declare_simd_clauses);
>>> +                       *omp_declare_simd_clauses);
>>
>> Instead of doing this indirection in all of the callers, let's change 
>> c_finish_omp_declare_simd to take a pointer as well, and do the 
>> indirection in initializing a reference variable at the top of the 
>> function.
> 
> Okay.
> 
>>
>>> +    sched_init_luids (bbs.to_vec ());
>>> +    haifa_init_h_i_d (bbs.to_vec ());
>>
>> Why are these to_vec changes needed when you are also changing the 
>> functions to take const&?
> 
> Calling to_vec() here isn't necessary so I've removed it.
> 
>>
>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
>>
>> Why not use a reference here and in other similar spots?
> 
> Sure, that works too.
> 
> Attached is what's left of the original changes now that r12-2418
> has been applied.

> @@ -3364,7 +3364,8 @@ static void
>  vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
>  			poly_uint64 min_value)
>  {
> -  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
> +  vec<vec_lower_bound> lower_bounds
> +    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
>    for (unsigned int i = 0; i < lower_bounds.length (); ++i)
>      if (operand_equal_p (lower_bounds[i].expr, expr, 0))
>        {
> @@ -3466,7 +3467,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
>    typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
>    hash_set <tree_pair_hash> compared_objects;
>  
> -  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
> +  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).to_vec ();

These could also be references.

That leaves this as the only remaining use of to_vec:

>    ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
> -    : m_known_vals (aavals->m_known_vals),
> -      m_known_contexts (aavals->m_known_contexts),
> -      m_known_aggs (aavals->m_known_aggs),
> -      m_known_value_ranges (aavals->m_known_value_ranges)
> +    : m_known_vals (aavals->m_known_vals.to_vec ()),
> +      m_known_contexts (aavals->m_known_contexts.to_vec ()),
> +      m_known_aggs (aavals->m_known_aggs.to_vec ()),
> +      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())

I think we could handle this by deriving ipa_auto_call_arg_values from 
ipa_call_arg_values like auto_vec is derived from vec, but perhaps 
dealing with the IPA datastructures could be saved for the next stage of 
overhauling vec.  Maybe for now just change the name to_vec to something 
clearer that new code shouldn't use it, e.g. to_vec_legacy.

Jason


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-20 20:08                                                   ` Jason Merrill
@ 2021-07-20 21:52                                                     ` Martin Sebor
  0 siblings, 0 replies; 59+ messages in thread
From: Martin Sebor @ 2021-07-20 21:52 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 6602 bytes --]

On 7/20/21 2:08 PM, Jason Merrill wrote:
> On 7/20/21 2:34 PM, Martin Sebor wrote:
>> On 7/14/21 10:23 AM, Jason Merrill wrote:
>>> On 7/14/21 10:46 AM, Martin Sebor wrote:
>>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>>>>> vec.h changes - I don't feel competent to assess all effects of 
>>>>>>>>> the change.
>>>>>>>>
>>>>>>>> They look OK to me except for:
>>>>>>>>
>>>>>>>> -extern vnull vNULL;
>>>>>>>> +static constexpr vnull vNULL{ };
>>>>>>>>
>>>>>>>> Making vNULL have static linkage can make it an ODR violation to 
>>>>>>>> use
>>>>>>>> vNULL in templates and inline functions, because different
>>>>>>>> instantiations will refer to a different "vNULL" in each 
>>>>>>>> translation
>>>>>>>> unit.
>>>>>>>
>>>>>>> The ODR says this is OK because it's a literal constant with the 
>>>>>>> same value (6.2/12.2.1).
>>>>>>>
>>>>>>> But it would be better without the explicit 'static'; then in 
>>>>>>> C++17 it's implicitly inline instead of static.
>>>>>>
>>>>>> I'll remove the static.
>>>>>>
>>>>>>>
>>>>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>>>>> blurring of the object/pointer boundary that is also dependent on 
>>>>>>> vec being a thin wrapper around a pointer.  In almost all cases 
>>>>>>> it can be replaced with {}; one exception is == comparison, where 
>>>>>>> it seems to be testing that the embedded pointer is null, which 
>>>>>>> is a weird thing to want to test.
>>>>>>
>>>>>> The one use case I know of for vNULL where I can't think of
>>>>>> an equally good substitute is in passing a vec as an argument by
>>>>>> value.  The only way to do that that I can think of is to name
>>>>>> the full vec type (i.e., the specialization) which is more typing
>>>>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>>>>> miss this trick if it were to be removed but others might feel
>>>>>> differently.
>>>>>
>>>>> In C++11, it can be replaced by {} in that context as well.
>>>>
>>>> Cool.  I thought I'd tried { } here but I guess not.
>>>>
>>>>>
>>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>>>>> of it left, unless there's some clever trick to make the removal
>>>>>> (mostly) effortless and seamless, I'd much rather do it independently
>>>>>> of this initial change. I also don't know if I can commit to making
>>>>>> all this cleanup.
>>>>>
>>>>> I already have a patch to replace all but one use of vNULL, but 
>>>>> I'll hold off with it until after your patch.
>>>>
>>>> So what's the next step?  The patch only removes a few uses of vNULL
>>>> but doesn't add any.  Is it good to go as is (without the static and
>>>> with the additional const changes Richard suggested)?  This patch is
>>>> attached to my reply to Richard:
>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
>>>
>>> As Richard wrote:
>>>
>>>> The pieces where you change vec<> passing to const vec<>& and the few
>>>> where you change vec<> * to const vec<> * are OK - this should make the
>>>> rest a smaller piece to review.
>>>
>>> Please go ahead and apply those changes and send a new patch with the 
>>> remainder of the changes.
>>
>> I have just pushed r12-2418:
>> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
>>
>>>
>>> A few other comments:
>>>
>>>> -                       omp_declare_simd_clauses);
>>>> +                       *omp_declare_simd_clauses);
>>>
>>> Instead of doing this indirection in all of the callers, let's change 
>>> c_finish_omp_declare_simd to take a pointer as well, and do the 
>>> indirection in initializing a reference variable at the top of the 
>>> function.
>>
>> Okay.
>>
>>>
>>>> +    sched_init_luids (bbs.to_vec ());
>>>> +    haifa_init_h_i_d (bbs.to_vec ());
>>>
>>> Why are these to_vec changes needed when you are also changing the 
>>> functions to take const&?
>>
>> Calling to_vec() here isn't necessary so I've removed it.
>>
>>>
>>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
>>>
>>> Why not use a reference here and in other similar spots?
>>
>> Sure, that works too.
>>
>> Attached is what's left of the original changes now that r12-2418
>> has been applied.
> 
>> @@ -3364,7 +3364,8 @@ static void
>>  vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool 
>> unsigned_p,
>>              poly_uint64 min_value)
>>  {
>> -  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS 
>> (loop_vinfo);
>> +  vec<vec_lower_bound> lower_bounds
>> +    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo).to_vec ();
>>    for (unsigned int i = 0; i < lower_bounds.length (); ++i)
>>      if (operand_equal_p (lower_bounds[i].expr, expr, 0))
>>        {
>> @@ -3466,7 +3467,7 @@ vect_prune_runtime_alias_test_list 
>> (loop_vec_info loop_vinfo)
>>    typedef pair_hash <tree_operand_hash, tree_operand_hash> 
>> tree_pair_hash;
>>    hash_set <tree_pair_hash> compared_objects;
>>
>> -  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
>> +  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS 
>> (loop_vinfo).to_vec ();
> 
> These could also be references.

Even const references it turns out for some of them.

> That leaves this as the only remaining use of to_vec:
> 
>>    ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
>> -    : m_known_vals (aavals->m_known_vals),
>> -      m_known_contexts (aavals->m_known_contexts),
>> -      m_known_aggs (aavals->m_known_aggs),
>> -      m_known_value_ranges (aavals->m_known_value_ranges)
>> +    : m_known_vals (aavals->m_known_vals.to_vec ()),
>> +      m_known_contexts (aavals->m_known_contexts.to_vec ()),
>> +      m_known_aggs (aavals->m_known_aggs.to_vec ()),
>> +      m_known_value_ranges (aavals->m_known_value_ranges.to_vec ())
> 
> I think we could handle this by deriving ipa_auto_call_arg_values from 
> ipa_call_arg_values like auto_vec is derived from vec, but perhaps 
> dealing with the IPA datastructures could be saved for the next stage of 
> overhauling vec.  Maybe for now just change the name to_vec to something 
> clearer that new code shouldn't use it, e.g. to_vec_legacy.

Done in the attached patch.

Martin

[-- Attachment #2: gcc-90904.diff --]
[-- Type: text/x-patch, Size: 22341 bytes --]

PR middle-end/90904 - vec assignment and copying undefined

gcc/ChangeLog:

	PR middle-end/90904
	* vec.c (test_copy_assign): New function.
	(vec_c_tests): Call it.
	* vec.h (vec_assign): New function.
	(auto_vec copy ctor): Define.
	(auto_vec::operator=): Define.
	(auto_vec_no_copy): New class template.
	(auto_string_vec): Disable copying/assignment.

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 9a56e0c04c6..fa3c9fa3a1b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1489,7 +1489,8 @@ static tree c_parser_std_attribute_specifier_sequence (c_parser *);
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
-					   bool, bool, tree *, vec<c_token>,
+					   bool, bool, tree * = NULL,
+					   vec<c_token> * = NULL,
 					   bool have_attrs = false,
 					   tree attrs = NULL,
 					   struct oacc_routine_data * = NULL,
@@ -1774,13 +1775,12 @@ c_parser_external_declaration (c_parser *parser)
 	 an @interface or @protocol with prefix attributes).  We can
 	 only tell which after parsing the declaration specifiers, if
 	 any, and the first declarator.  */
-      c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				     NULL, vNULL);
+      c_parser_declaration_or_fndef (parser, true, true, true, false, true);
       break;
     }
 }
 
-static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token>);
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> *);
 static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
 
 /* Build and add a DEBUG_BEGIN_STMT statement with location LOC.  */
@@ -1890,11 +1890,15 @@ static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			       bool static_assert_ok, bool empty_ok,
 			       bool nested, bool start_attr_ok,
-			       tree *objc_foreach_object_declaration,
-			       vec<c_token> omp_declare_simd_clauses,
-			       bool have_attrs, tree attrs,
-			       struct oacc_routine_data *oacc_routine_data,
-			       bool *fallthru_attr_p)
+			       tree *objc_foreach_object_declaration
+			       /* = NULL */,
+			       vec<c_token> *omp_declare_simd_clauses
+			       /* = NULL */,
+			       bool have_attrs /* = false */,
+			       tree attrs /* = NULL_TREE */,
+			       struct oacc_routine_data *oacc_routine_data
+			       /* = NULL */,
+			       bool *fallthru_attr_p /* = NULL */)
 {
   struct c_declspecs *specs;
   tree prefix_attrs;
@@ -2150,7 +2154,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 					C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
 	{
-	  if (omp_declare_simd_clauses.exists ())
+	  if (omp_declare_simd_clauses)
 	    c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
 				       omp_declare_simd_clauses);
 	  if (oacc_routine_data)
@@ -2250,7 +2254,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		}
@@ -2262,7 +2266,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 				  chainon (postfix_attrs, all_prefix_attrs));
 		  if (!d)
 		    d = error_mark_node;
-		  if (omp_declare_simd_clauses.exists ())
+		  if (omp_declare_simd_clauses)
 		    c_finish_omp_declare_simd (parser, d, NULL_TREE,
 					       omp_declare_simd_clauses);
 		  init_loc = c_parser_peek_token (parser)->location;
@@ -2342,7 +2346,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      warn_parm_array_mismatch (lastloc, d, parms);
 		    }
 		}
-	      if (omp_declare_simd_clauses.exists ())
+	      if (omp_declare_simd_clauses)
 		{
 		  tree parms = NULL_TREE;
 		  if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2496,9 +2500,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       while (c_parser_next_token_is_not (parser, CPP_EOF)
 	     && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
 	c_parser_declaration_or_fndef (parser, false, false, false,
-				       true, false, NULL, vNULL);
+				       true, false);
       store_parm_decls ();
-      if (omp_declare_simd_clauses.exists ())
+      if (omp_declare_simd_clauses)
 	c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
 				   omp_declare_simd_clauses);
       if (oacc_routine_data)
@@ -5699,7 +5703,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
-					 vNULL, have_std_attrs, std_attrs,
+					 NULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
 
 	  if (last_stmt && !fallthru_attr_p)
@@ -5731,7 +5735,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	      last_label = false;
 	      mark_valid_location_for_stdc_pragma (false);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, vNULL);
+					     true);
 	      /* Following the old parser, __extension__ does not
 		 disable this diagnostic.  */
 	      restore_extension_diagnostics (ext);
@@ -6782,7 +6786,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	       || c_parser_nth_token_starts_std_attributes (parser, 1))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
-					 &object_expression, vNULL);
+					 &object_expression);
 	  parser->objc_could_be_foreach_context = false;
 	  
 	  if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -6813,7 +6817,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
 	      ext = disable_extension_diagnostics ();
 	      c_parser_consume_token (parser);
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, &object_expression, vNULL);
+					     true, &object_expression);
 	      parser->objc_could_be_foreach_context = false;
 	      
 	      restore_extension_diagnostics (ext);
@@ -11277,7 +11281,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
 	    }
 	  else
 	    c_parser_declaration_or_fndef (parser, false, false, true,
-					   false, true, NULL, vNULL);
+					   false, true);
 	  break;
 	}
     }
@@ -17273,12 +17277,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, vNULL, false, NULL, &data);
+					 NULL, NULL, false, NULL, &data);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, vNULL, false, NULL, &data);
+				       NULL, NULL, false, NULL, &data);
     }
 }
 
@@ -18385,8 +18389,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
 	    vec_safe_push (for_block, c_begin_compound_stmt (true));
 	  this_pre_body = push_stmt_list ();
 	  c_in_omp_for = true;
-	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, vNULL);
+	  c_parser_declaration_or_fndef (parser, true, true, true, true, true);
 	  c_in_omp_for = false;
 	  if (this_pre_body)
 	    {
@@ -20327,12 +20330,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  while (c_parser_next_token_is (parser, CPP_KEYWORD)
 		 && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
 	  c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  restore_extension_diagnostics (ext);
 	}
       else
 	c_parser_declaration_or_fndef (parser, true, true, true, false, true,
-				       NULL, clauses);
+				       NULL, &clauses);
       break;
     case pragma_struct:
     case pragma_param:
@@ -20353,7 +20356,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
 	  if (c_parser_next_tokens_start_declaration (parser))
 	    {
 	      c_parser_declaration_or_fndef (parser, true, true, true, true,
-					     true, NULL, clauses);
+					     true, NULL, &clauses);
 	      restore_extension_diagnostics (ext);
 	      break;
 	    }
@@ -20362,7 +20365,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
       else if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  c_parser_declaration_or_fndef (parser, true, true, true, true, true,
-					 NULL, clauses);
+					 NULL, &clauses);
 	  break;
 	}
       error ("%<#pragma omp declare %s%> must be followed by "
@@ -20843,8 +20846,10 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
 
 static void
 c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
-			   vec<c_token> clauses)
+			   vec<c_token> *pclauses)
 {
+  vec<c_token> &clauses = *pclauses;
+
   /* Normally first token is CPP_NAME "simd" or "variant".  CPP_EOF there
      indicates error has been reported and CPP_PRAGMA that
      c_finish_omp_declare_simd has already processed the tokens.  */
diff --git a/gcc/dominance.c b/gcc/dominance.c
index 6a262ce8283..cc63391a39a 100644
--- a/gcc/dominance.c
+++ b/gcc/dominance.c
@@ -1227,7 +1227,7 @@ recompute_dominator (enum cdi_direction dir, basic_block bb)
    from BBS.  */
 
 static void
-prune_bbs_to_update_dominators (vec<basic_block> bbs,
+prune_bbs_to_update_dominators (vec<basic_block> &bbs,
 				bool conservative)
 {
   unsigned i;
@@ -1379,7 +1379,7 @@ determine_dominators_for_sons (struct graph *g, vec<basic_block> bbs,
    a block of BBS in the current dominance tree dominate it.  */
 
 void
-iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> bbs,
+iterate_fix_dominators (enum cdi_direction dir, vec<basic_block> &bbs,
 			bool conservative)
 {
   unsigned i;
diff --git a/gcc/dominance.h b/gcc/dominance.h
index 1a8c248ee98..970da02c594 100644
--- a/gcc/dominance.h
+++ b/gcc/dominance.h
@@ -78,7 +78,7 @@ checking_verify_dominators (cdi_direction dir)
 
 basic_block recompute_dominator (enum cdi_direction, basic_block);
 extern void iterate_fix_dominators (enum cdi_direction,
-				    vec<basic_block> , bool);
+				    vec<basic_block> &, bool);
 extern void add_to_dominance_info (enum cdi_direction, basic_block);
 extern void delete_from_dominance_info (enum cdi_direction, basic_block);
 extern basic_block first_dom_son (enum cdi_direction, basic_block);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 2fe220acf84..579c5bca516 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -499,10 +499,10 @@ public:
      get reallocated, the member vectors and the underlying auto_vecs would get
      out of sync.  */
   ipa_call_arg_values (ipa_auto_call_arg_values *aavals)
-    : m_known_vals (aavals->m_known_vals),
-      m_known_contexts (aavals->m_known_contexts),
-      m_known_aggs (aavals->m_known_aggs),
-      m_known_value_ranges (aavals->m_known_value_ranges)
+    : m_known_vals (aavals->m_known_vals.to_vec_legacy ()),
+      m_known_contexts (aavals->m_known_contexts.to_vec_legacy ()),
+      m_known_aggs (aavals->m_known_aggs.to_vec_legacy ()),
+      m_known_value_ranges (aavals->m_known_value_ranges.to_vec_legacy ())
   {}
 
   /* If m_known_vals (vector of known "scalar" values) is sufficiantly long,
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index d2a7395dd8f..ebe95cc6c73 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3107,7 +3107,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
 
 static bool
 insert_into_preds_of_block (basic_block block, unsigned int exprnum,
-			    vec<pre_expr> avail)
+			    vec<pre_expr> &avail)
 {
   pre_expr expr = expression_for_id (exprnum);
   pre_expr newphi;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 6995efba899..415ca01a02b 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -212,7 +212,7 @@ vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 static void
 vect_check_nonzero_value (loop_vec_info loop_vinfo, tree value)
 {
-  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
+  const vec<tree> &checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
   for (unsigned int i = 0; i < checks.length(); ++i)
     if (checks[i] == value)
       return;
@@ -2349,8 +2349,8 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
 
   if (do_versioning)
     {
-      vec<stmt_vec_info> may_misalign_stmts
-        = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
+      const vec<stmt_vec_info> &may_misalign_stmts
+	= LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo);
       stmt_vec_info stmt_info;
 
       /* It can now be assumed that the data references in the statements
@@ -3364,7 +3364,8 @@ static void
 vect_check_lower_bound (loop_vec_info loop_vinfo, tree expr, bool unsigned_p,
 			poly_uint64 min_value)
 {
-  vec<vec_lower_bound> lower_bounds = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
+  vec<vec_lower_bound> &lower_bounds
+    = LOOP_VINFO_LOWER_BOUNDS (loop_vinfo);
   for (unsigned int i = 0; i < lower_bounds.length (); ++i)
     if (operand_equal_p (lower_bounds[i].expr, expr, 0))
       {
@@ -3466,10 +3467,10 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
   hash_set <tree_pair_hash> compared_objects;
 
-  vec<ddr_p> may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
+  const vec<ddr_p> &may_alias_ddrs = LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
   vec<dr_with_seg_len_pair_t> &comp_alias_ddrs
     = LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
-  vec<vec_object_pair> &check_unequal_addrs
+  const vec<vec_object_pair> &check_unequal_addrs
     = LOOP_VINFO_CHECK_UNEQUAL_ADDRS (loop_vinfo);
   poly_uint64 vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
   tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo);
@@ -5339,7 +5340,7 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
    I4:  6 14 22 30  7 15 23 31.  */
 
 void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> dr_chain,
+vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
 			  unsigned int length,
 			  stmt_vec_info stmt_info,
 			  gimple_stmt_iterator *gsi,
diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c
index ad209deca79..b8d09b7832e 100644
--- a/gcc/tree-vect-slp-patterns.c
+++ b/gcc/tree-vect-slp-patterns.c
@@ -746,7 +746,7 @@ vect_match_call_complex_mla (slp_tree node, unsigned child,
    of the negate node.  */
 
 static inline bool
-vect_normalize_conj_loc (vec<slp_tree> args, bool *neg_first_p = NULL)
+vect_normalize_conj_loc (vec<slp_tree> &args, bool *neg_first_p = NULL)
 {
   gcc_assert (args.length () == 2);
   bool neg_found = false;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index d71552296bb..d88f65f3550 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -4462,7 +4462,7 @@ static void
 vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
 				       int multi_step_cvt,
 				       stmt_vec_info stmt_info,
-				       vec<tree> vec_dsts,
+				       vec<tree> &vec_dsts,
 				       gimple_stmt_iterator *gsi,
 				       slp_tree slp_node, enum tree_code code)
 {
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index deb22477e28..45b61fa4793 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1990,8 +1990,8 @@ extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT);
 extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
 extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
 extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool);
-extern void vect_permute_store_chain (vec_info *,
-				      vec<tree> ,unsigned int, stmt_vec_info,
+extern void vect_permute_store_chain (vec_info *, vec<tree> &,
+				      unsigned int, stmt_vec_info,
 				      gimple_stmt_iterator *, vec<tree> *);
 extern tree vect_setup_realignment (vec_info *,
 				    stmt_vec_info, gimple_stmt_iterator *,
diff --git a/gcc/vec.c b/gcc/vec.c
index f9dbb2cac31..6d767cc12c1 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -38,16 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #endif
 
-/* vNULL is an empty type with a template cast operation that returns
-   a zero-initialized vec<T, A, L> instance.  Use this when you want
-   to assign nil values to new vec instances or pass a nil vector as
-   a function call argument.
-
-   We use this technique because vec<T, A, L> must be PODs (they are
-   stored in unions and passed in vararg functions), this means that
-   they cannot have ctors/dtors.  */
-vnull vNULL;
-
 /* Vector memory usage.  */
 class vec_usage: public mem_usage
 {
@@ -282,6 +272,42 @@ safe_push_range (vec <int>&v, int start, int limit)
     v.safe_push (i);
 }
 
+/* Verify forms of initialization.  */
+
+static void
+test_init ()
+{
+  {
+    vec<int> v1{ };
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 = vec<int>();
+    ASSERT_EQ (0, v1.length ());
+
+    vec<int> v2 = v1;
+    ASSERT_EQ (0, v2.length ());
+  }
+
+  {
+    vec<int> v1 (vNULL);
+    ASSERT_EQ (0, v1.length ());
+    v1.safe_push (1);
+
+    vec<int> v2 (v1);
+    ASSERT_EQ (1, v1.length ());
+    v2.safe_push (1);
+
+    ASSERT_EQ (2, v1.length ());
+    ASSERT_EQ (2, v2.length ());
+    v1.release ();
+  }
+}
+
 /* Verify that vec::quick_push works correctly.  */
 
 static void
@@ -547,6 +573,7 @@ test_auto_delete_vec ()
 void
 vec_c_tests ()
 {
+  test_init ();
   test_quick_push ();
   test_safe_push ();
   test_truncate ();
diff --git a/gcc/vec.h b/gcc/vec.h
index 30ef9a69473..b3f47b1f65b 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -541,18 +541,16 @@ vec_copy_construct (T *dst, const T *src, unsigned n)
     ::new (static_cast<void*>(dst)) T (*src);
 }
 
-/* Type to provide NULL values for vec<T, A, L>.  This is used to
-   provide nil initializers for vec instances.  Since vec must be
-   a POD, we cannot have proper ctor/dtor for it.  To initialize
-   a vec instance, you can assign it the value vNULL.  This isn't
-   needed for file-scope and function-local static vectors, which
-   are zero-initialized by default.  */
-struct vnull
-{
-  template <typename T, typename A, typename L>
-  CONSTEXPR operator vec<T, A, L> () const { return vec<T, A, L>(); }
-};
-extern vnull vNULL;
+/* Type to provide zero-initialized values for vec<T, A, L>.  This is
+   used to  provide nil initializers for vec instances.  Since vec must
+   be a trivially copyable type that can be copied by memcpy and zeroed
+   out by memset, it must have defaulted default and copy ctor and copy
+   assignment.  To initialize a vec either use value initialization
+   (e.g., vec() or vec v{ };) or assign it the value vNULL.  This isn't
+   needed for file-scope and function-local static vectors, which are
+   zero-initialized by default.  */
+struct vnull { };
+constexpr vnull vNULL{ };
 
 
 /* Embeddable vector.  These vectors are suitable to be embedded
@@ -1431,10 +1429,34 @@ gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
    As long as we use C++03, we cannot have constructors nor
    destructors in classes that are stored in unions.  */
 
+template<typename T, size_t N = 0>
+class auto_vec;
+
 template<typename T>
 struct vec<T, va_heap, vl_ptr>
 {
 public:
+  /* Default ctors to ensure triviality.  Use value-initialization
+     (e.g., vec() or vec v{ };) or vNULL to create a zero-initialized
+     instance.  */
+  vec () = default;
+  vec (const vec &) = default;
+  /* Initialization from the generic vNULL.  */
+  vec (vnull): m_vec () { }
+  /* Same as default ctor: vec storage must be released manually.  */
+  ~vec () = default;
+
+  /* Defaulted same as copy ctor.  */
+  vec& operator= (const vec &) = default;
+
+  /* Prevent implicit conversion from auto_vec.  Use auto_vec::to_vec()
+     instead.  */
+  template <size_t N>
+  vec (auto_vec<T, N> &) = delete;
+
+  template <size_t N>
+  void operator= (auto_vec<T, N> &) = delete;
+
   /* Memory allocation and deallocation for the embedded vector.
      Needed because we cannot have proper ctors/dtors defined.  */
   void create (unsigned nelems CXX_MEM_STAT_INFO);
@@ -1522,7 +1544,7 @@ public:
    want to ask for internal storage for vectors on the stack because if the
    size of the vector is larger than the internal storage that space is wasted.
    */
-template<typename T, size_t N = 0>
+template<typename T, size_t N /* = 0 */>
 class auto_vec : public vec<T, va_heap>
 {
 public:
@@ -1549,6 +1571,14 @@ public:
     this->release ();
   }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.
+     This is a legacy function not to be used in new code.  */
+  vec<T, va_heap> to_vec_legacy () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
 private:
   vec<T, va_heap, vl_embed> m_auto;
   T m_data[MAX (N - 1, 1)];
@@ -1602,6 +1632,14 @@ public:
       return *this;
     }
 
+  /* Explicitly convert to the base class.  There is no conversion
+     from a const auto_vec because a copy of the returned vec can
+     be used to modify *THIS.
+     This is a legacy function not to be used in new code.  */
+  vec<T, va_heap> to_vec_legacy () {
+    return *static_cast<vec<T, va_heap> *>(this);
+  }
+
   // 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 ().
@@ -1781,7 +1819,7 @@ template<typename T>
 inline vec<T, va_heap, vl_ptr>
 vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECL) const
 {
-  vec<T, va_heap, vl_ptr> new_vec = vNULL;
+  vec<T, va_heap, vl_ptr> new_vec{ };
   if (length ())
     new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT);
   return new_vec;

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-20 18:34                                                 ` Martin Sebor
  2021-07-20 20:08                                                   ` Jason Merrill
@ 2021-07-27 18:56                                                   ` Martin Sebor
  2021-07-30 15:06                                                     ` Jason Merrill
  1 sibling, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-07-27 18:56 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575690.html

Are there any other suggestions or comments or is the latest revision
okay to commit?

On 7/20/21 12:34 PM, Martin Sebor wrote:
> On 7/14/21 10:23 AM, Jason Merrill wrote:
>> On 7/14/21 10:46 AM, Martin Sebor wrote:
>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>>>> vec.h changes - I don't feel competent to assess all effects of 
>>>>>>>> the change.
>>>>>>>
>>>>>>> They look OK to me except for:
>>>>>>>
>>>>>>> -extern vnull vNULL;
>>>>>>> +static constexpr vnull vNULL{ };
>>>>>>>
>>>>>>> Making vNULL have static linkage can make it an ODR violation to use
>>>>>>> vNULL in templates and inline functions, because different
>>>>>>> instantiations will refer to a different "vNULL" in each translation
>>>>>>> unit.
>>>>>>
>>>>>> The ODR says this is OK because it's a literal constant with the 
>>>>>> same value (6.2/12.2.1).
>>>>>>
>>>>>> But it would be better without the explicit 'static'; then in 
>>>>>> C++17 it's implicitly inline instead of static.
>>>>>
>>>>> I'll remove the static.
>>>>>
>>>>>>
>>>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>>>> blurring of the object/pointer boundary that is also dependent on 
>>>>>> vec being a thin wrapper around a pointer.  In almost all cases it 
>>>>>> can be replaced with {}; one exception is == comparison, where it 
>>>>>> seems to be testing that the embedded pointer is null, which is a 
>>>>>> weird thing to want to test.
>>>>>
>>>>> The one use case I know of for vNULL where I can't think of
>>>>> an equally good substitute is in passing a vec as an argument by
>>>>> value.  The only way to do that that I can think of is to name
>>>>> the full vec type (i.e., the specialization) which is more typing
>>>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>>>> miss this trick if it were to be removed but others might feel
>>>>> differently.
>>>>
>>>> In C++11, it can be replaced by {} in that context as well.
>>>
>>> Cool.  I thought I'd tried { } here but I guess not.
>>>
>>>>
>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>>>> of it left, unless there's some clever trick to make the removal
>>>>> (mostly) effortless and seamless, I'd much rather do it independently
>>>>> of this initial change. I also don't know if I can commit to making
>>>>> all this cleanup.
>>>>
>>>> I already have a patch to replace all but one use of vNULL, but I'll 
>>>> hold off with it until after your patch.
>>>
>>> So what's the next step?  The patch only removes a few uses of vNULL
>>> but doesn't add any.  Is it good to go as is (without the static and
>>> with the additional const changes Richard suggested)?  This patch is
>>> attached to my reply to Richard:
>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
>>
>> As Richard wrote:
>>
>>> The pieces where you change vec<> passing to const vec<>& and the few
>>> where you change vec<> * to const vec<> * are OK - this should make the
>>> rest a smaller piece to review.
>>
>> Please go ahead and apply those changes and send a new patch with the 
>> remainder of the changes.
> 
> I have just pushed r12-2418:
> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
> 
>>
>> A few other comments:
>>
>>> -                       omp_declare_simd_clauses);
>>> +                       *omp_declare_simd_clauses);
>>
>> Instead of doing this indirection in all of the callers, let's change 
>> c_finish_omp_declare_simd to take a pointer as well, and do the 
>> indirection in initializing a reference variable at the top of the 
>> function.
> 
> Okay.
> 
>>
>>> +    sched_init_luids (bbs.to_vec ());
>>> +    haifa_init_h_i_d (bbs.to_vec ());
>>
>> Why are these to_vec changes needed when you are also changing the 
>> functions to take const&?
> 
> Calling to_vec() here isn't necessary so I've removed it.
> 
>>
>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
>>
>> Why not use a reference here and in other similar spots?
> 
> Sure, that works too.
> 
> Attached is what's left of the original changes now that r12-2418
> has been applied.
> 
> Martin


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-27 18:56                                                   ` Martin Sebor
@ 2021-07-30 15:06                                                     ` Jason Merrill
  2021-08-06  2:07                                                       ` Martin Sebor
  0 siblings, 1 reply; 59+ messages in thread
From: Jason Merrill @ 2021-07-30 15:06 UTC (permalink / raw)
  To: Martin Sebor, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/27/21 2:56 PM, Martin Sebor wrote:
> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575690.html
> 
> Are there any other suggestions or comments or is the latest revision
> okay to commit?

OK.

> On 7/20/21 12:34 PM, Martin Sebor wrote:
>> On 7/14/21 10:23 AM, Jason Merrill wrote:
>>> On 7/14/21 10:46 AM, Martin Sebor wrote:
>>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>>>>> vec.h changes - I don't feel competent to assess all effects of 
>>>>>>>>> the change.
>>>>>>>>
>>>>>>>> They look OK to me except for:
>>>>>>>>
>>>>>>>> -extern vnull vNULL;
>>>>>>>> +static constexpr vnull vNULL{ };
>>>>>>>>
>>>>>>>> Making vNULL have static linkage can make it an ODR violation to 
>>>>>>>> use
>>>>>>>> vNULL in templates and inline functions, because different
>>>>>>>> instantiations will refer to a different "vNULL" in each 
>>>>>>>> translation
>>>>>>>> unit.
>>>>>>>
>>>>>>> The ODR says this is OK because it's a literal constant with the 
>>>>>>> same value (6.2/12.2.1).
>>>>>>>
>>>>>>> But it would be better without the explicit 'static'; then in 
>>>>>>> C++17 it's implicitly inline instead of static.
>>>>>>
>>>>>> I'll remove the static.
>>>>>>
>>>>>>>
>>>>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>>>>> blurring of the object/pointer boundary that is also dependent on 
>>>>>>> vec being a thin wrapper around a pointer.  In almost all cases 
>>>>>>> it can be replaced with {}; one exception is == comparison, where 
>>>>>>> it seems to be testing that the embedded pointer is null, which 
>>>>>>> is a weird thing to want to test.
>>>>>>
>>>>>> The one use case I know of for vNULL where I can't think of
>>>>>> an equally good substitute is in passing a vec as an argument by
>>>>>> value.  The only way to do that that I can think of is to name
>>>>>> the full vec type (i.e., the specialization) which is more typing
>>>>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>>>>> miss this trick if it were to be removed but others might feel
>>>>>> differently.
>>>>>
>>>>> In C++11, it can be replaced by {} in that context as well.
>>>>
>>>> Cool.  I thought I'd tried { } here but I guess not.
>>>>
>>>>>
>>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>>>>> of it left, unless there's some clever trick to make the removal
>>>>>> (mostly) effortless and seamless, I'd much rather do it independently
>>>>>> of this initial change. I also don't know if I can commit to making
>>>>>> all this cleanup.
>>>>>
>>>>> I already have a patch to replace all but one use of vNULL, but 
>>>>> I'll hold off with it until after your patch.
>>>>
>>>> So what's the next step?  The patch only removes a few uses of vNULL
>>>> but doesn't add any.  Is it good to go as is (without the static and
>>>> with the additional const changes Richard suggested)?  This patch is
>>>> attached to my reply to Richard:
>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
>>>
>>> As Richard wrote:
>>>
>>>> The pieces where you change vec<> passing to const vec<>& and the few
>>>> where you change vec<> * to const vec<> * are OK - this should make the
>>>> rest a smaller piece to review.
>>>
>>> Please go ahead and apply those changes and send a new patch with the 
>>> remainder of the changes.
>>
>> I have just pushed r12-2418:
>> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
>>
>>>
>>> A few other comments:
>>>
>>>> -                       omp_declare_simd_clauses);
>>>> +                       *omp_declare_simd_clauses);
>>>
>>> Instead of doing this indirection in all of the callers, let's change 
>>> c_finish_omp_declare_simd to take a pointer as well, and do the 
>>> indirection in initializing a reference variable at the top of the 
>>> function.
>>
>> Okay.
>>
>>>
>>>> +    sched_init_luids (bbs.to_vec ());
>>>> +    haifa_init_h_i_d (bbs.to_vec ());
>>>
>>> Why are these to_vec changes needed when you are also changing the 
>>> functions to take const&?
>>
>> Calling to_vec() here isn't necessary so I've removed it.
>>
>>>
>>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
>>>
>>> Why not use a reference here and in other similar spots?
>>
>> Sure, that works too.
>>
>> Attached is what's left of the original changes now that r12-2418
>> has been applied.
>>
>> Martin
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-07-30 15:06                                                     ` Jason Merrill
@ 2021-08-06  2:07                                                       ` Martin Sebor
  2021-08-06  7:52                                                         ` Christophe Lyon
  0 siblings, 1 reply; 59+ messages in thread
From: Martin Sebor @ 2021-08-06  2:07 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Richard Biener; +Cc: gcc-patches

On 7/30/21 9:06 AM, Jason Merrill wrote:
> On 7/27/21 2:56 PM, Martin Sebor wrote:
>> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575690.html
>>
>> Are there any other suggestions or comments or is the latest revision
>> okay to commit?
> 
> OK.

I had to make a few more adjustments to fix up code that's snuck
in since I last tested the patch.  I committed r12-2776 after
retesting on x86_64-linux.

With the cleanup out of the way I'll resubmit the copy ctor patch
next.

Martin

> 
>> On 7/20/21 12:34 PM, Martin Sebor wrote:
>>> On 7/14/21 10:23 AM, Jason Merrill wrote:
>>>> On 7/14/21 10:46 AM, Martin Sebor wrote:
>>>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>>>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>>>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>>>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>>>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>>>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>>>>>>>>>> vec.h changes - I don't feel competent to assess all effects 
>>>>>>>>>> of the change.
>>>>>>>>>
>>>>>>>>> They look OK to me except for:
>>>>>>>>>
>>>>>>>>> -extern vnull vNULL;
>>>>>>>>> +static constexpr vnull vNULL{ };
>>>>>>>>>
>>>>>>>>> Making vNULL have static linkage can make it an ODR violation 
>>>>>>>>> to use
>>>>>>>>> vNULL in templates and inline functions, because different
>>>>>>>>> instantiations will refer to a different "vNULL" in each 
>>>>>>>>> translation
>>>>>>>>> unit.
>>>>>>>>
>>>>>>>> The ODR says this is OK because it's a literal constant with the 
>>>>>>>> same value (6.2/12.2.1).
>>>>>>>>
>>>>>>>> But it would be better without the explicit 'static'; then in 
>>>>>>>> C++17 it's implicitly inline instead of static.
>>>>>>>
>>>>>>> I'll remove the static.
>>>>>>>
>>>>>>>>
>>>>>>>> But then, do we really want to keep vNULL at all?  It's a weird 
>>>>>>>> blurring of the object/pointer boundary that is also dependent 
>>>>>>>> on vec being a thin wrapper around a pointer.  In almost all 
>>>>>>>> cases it can be replaced with {}; one exception is == 
>>>>>>>> comparison, where it seems to be testing that the embedded 
>>>>>>>> pointer is null, which is a weird thing to want to test.
>>>>>>>
>>>>>>> The one use case I know of for vNULL where I can't think of
>>>>>>> an equally good substitute is in passing a vec as an argument by
>>>>>>> value.  The only way to do that that I can think of is to name
>>>>>>> the full vec type (i.e., the specialization) which is more typing
>>>>>>> and less generic than vNULL.  I don't use vNULL myself so I wouldn't
>>>>>>> miss this trick if it were to be removed but others might feel
>>>>>>> differently.
>>>>>>
>>>>>> In C++11, it can be replaced by {} in that context as well.
>>>>>
>>>>> Cool.  I thought I'd tried { } here but I guess not.
>>>>>
>>>>>>
>>>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>>>>>>> of it left, unless there's some clever trick to make the removal
>>>>>>> (mostly) effortless and seamless, I'd much rather do it 
>>>>>>> independently
>>>>>>> of this initial change. I also don't know if I can commit to making
>>>>>>> all this cleanup.
>>>>>>
>>>>>> I already have a patch to replace all but one use of vNULL, but 
>>>>>> I'll hold off with it until after your patch.
>>>>>
>>>>> So what's the next step?  The patch only removes a few uses of vNULL
>>>>> but doesn't add any.  Is it good to go as is (without the static and
>>>>> with the additional const changes Richard suggested)?  This patch is
>>>>> attached to my reply to Richard:
>>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
>>>>
>>>> As Richard wrote:
>>>>
>>>>> The pieces where you change vec<> passing to const vec<>& and the few
>>>>> where you change vec<> * to const vec<> * are OK - this should make 
>>>>> the
>>>>> rest a smaller piece to review.
>>>>
>>>> Please go ahead and apply those changes and send a new patch with 
>>>> the remainder of the changes.
>>>
>>> I have just pushed r12-2418:
>>> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
>>>
>>>>
>>>> A few other comments:
>>>>
>>>>> -                       omp_declare_simd_clauses);
>>>>> +                       *omp_declare_simd_clauses);
>>>>
>>>> Instead of doing this indirection in all of the callers, let's 
>>>> change c_finish_omp_declare_simd to take a pointer as well, and do 
>>>> the indirection in initializing a reference variable at the top of 
>>>> the function.
>>>
>>> Okay.
>>>
>>>>
>>>>> +    sched_init_luids (bbs.to_vec ());
>>>>> +    haifa_init_h_i_d (bbs.to_vec ());
>>>>
>>>> Why are these to_vec changes needed when you are also changing the 
>>>> functions to take const&?
>>>
>>> Calling to_vec() here isn't necessary so I've removed it.
>>>
>>>>
>>>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>>>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec ();
>>>>
>>>> Why not use a reference here and in other similar spots?
>>>
>>> Sure, that works too.
>>>
>>> Attached is what's left of the original changes now that r12-2418
>>> has been applied.
>>>
>>> Martin
>>
> 


^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-08-06  2:07                                                       ` Martin Sebor
@ 2021-08-06  7:52                                                         ` Christophe Lyon
  2021-08-06 12:17                                                           ` Christophe Lyon
  0 siblings, 1 reply; 59+ messages in thread
From: Christophe Lyon @ 2021-08-06  7:52 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, Jonathan Wakely, Richard Biener, gcc-patches

On Fri, Aug 6, 2021 at 4:07 AM Martin Sebor via Gcc-patches <
gcc-patches@gcc.gnu.org> wrote:

> On 7/30/21 9:06 AM, Jason Merrill wrote:
> > On 7/27/21 2:56 PM, Martin Sebor wrote:
> >> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575690.html
> >>
> >> Are there any other suggestions or comments or is the latest revision
> >> okay to commit?
> >
> > OK.
>
> I had to make a few more adjustments to fix up code that's snuck
> in since I last tested the patch.  I committed r12-2776 after
> retesting on x86_64-linux.
>
> With the cleanup out of the way I'll resubmit the copy ctor patch
> next.
>
>
Hi Martin,

Your patch breaks the aarch64 build:
 /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:
In function 'void aarch64_sve::register_svpattern()':
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:3502:27:
error: use of deleted function 'vec<T>::vec(auto_vec<T, N>&) [with long
unsigned int N = 32ul;
T = std::pair<const char*, int>]'
        "svpattern", values);
                           ^
In file included from
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/hash-table.h:248:0,
                 from
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/coretypes.h:480,
                 from
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:24:
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/vec.h:1455:3:
error: declared here
   vec (auto_vec<T, N> &) = delete;
   ^
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:
In function 'void aarch64_sve::register_svprfop()':
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:3516:30:
error: use of deleted function 'vec<T>::vec(auto_vec<T, N>&) [with long
unsigned int N = 16ul;
T = std::pair<const char*, int>]'
             "svprfop", values);
                              ^
In file included from
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/hash-table.h:248:0,
                 from
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/coretypes.h:480,
                 from
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:24:
/tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/vec.h:1455:3:
error: declared here
   vec (auto_vec<T, N> &) = delete;
   ^

Can you check?

Thanks,

Christophe

>
> Martin
>
> >
> >> On 7/20/21 12:34 PM, Martin Sebor wrote:
> >>> On 7/14/21 10:23 AM, Jason Merrill wrote:
> >>>> On 7/14/21 10:46 AM, Martin Sebor wrote:
> >>>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
> >>>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
> >>>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
> >>>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
> >>>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
> >>>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
> >>>>>>>>>> vec.h changes - I don't feel competent to assess all effects
> >>>>>>>>>> of the change.
> >>>>>>>>>
> >>>>>>>>> They look OK to me except for:
> >>>>>>>>>
> >>>>>>>>> -extern vnull vNULL;
> >>>>>>>>> +static constexpr vnull vNULL{ };
> >>>>>>>>>
> >>>>>>>>> Making vNULL have static linkage can make it an ODR violation
> >>>>>>>>> to use
> >>>>>>>>> vNULL in templates and inline functions, because different
> >>>>>>>>> instantiations will refer to a different "vNULL" in each
> >>>>>>>>> translation
> >>>>>>>>> unit.
> >>>>>>>>
> >>>>>>>> The ODR says this is OK because it's a literal constant with the
> >>>>>>>> same value (6.2/12.2.1).
> >>>>>>>>
> >>>>>>>> But it would be better without the explicit 'static'; then in
> >>>>>>>> C++17 it's implicitly inline instead of static.
> >>>>>>>
> >>>>>>> I'll remove the static.
> >>>>>>>
> >>>>>>>>
> >>>>>>>> But then, do we really want to keep vNULL at all?  It's a weird
> >>>>>>>> blurring of the object/pointer boundary that is also dependent
> >>>>>>>> on vec being a thin wrapper around a pointer.  In almost all
> >>>>>>>> cases it can be replaced with {}; one exception is ==
> >>>>>>>> comparison, where it seems to be testing that the embedded
> >>>>>>>> pointer is null, which is a weird thing to want to test.
> >>>>>>>
> >>>>>>> The one use case I know of for vNULL where I can't think of
> >>>>>>> an equally good substitute is in passing a vec as an argument by
> >>>>>>> value.  The only way to do that that I can think of is to name
> >>>>>>> the full vec type (i.e., the specialization) which is more typing
> >>>>>>> and less generic than vNULL.  I don't use vNULL myself so I
> wouldn't
> >>>>>>> miss this trick if it were to be removed but others might feel
> >>>>>>> differently.
> >>>>>>
> >>>>>> In C++11, it can be replaced by {} in that context as well.
> >>>>>
> >>>>> Cool.  I thought I'd tried { } here but I guess not.
> >>>>>
> >>>>>>
> >>>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
> >>>>>>> of it left, unless there's some clever trick to make the removal
> >>>>>>> (mostly) effortless and seamless, I'd much rather do it
> >>>>>>> independently
> >>>>>>> of this initial change. I also don't know if I can commit to making
> >>>>>>> all this cleanup.
> >>>>>>
> >>>>>> I already have a patch to replace all but one use of vNULL, but
> >>>>>> I'll hold off with it until after your patch.
> >>>>>
> >>>>> So what's the next step?  The patch only removes a few uses of vNULL
> >>>>> but doesn't add any.  Is it good to go as is (without the static and
> >>>>> with the additional const changes Richard suggested)?  This patch is
> >>>>> attached to my reply to Richard:
> >>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
> >>>>
> >>>> As Richard wrote:
> >>>>
> >>>>> The pieces where you change vec<> passing to const vec<>& and the few
> >>>>> where you change vec<> * to const vec<> * are OK - this should make
> >>>>> the
> >>>>> rest a smaller piece to review.
> >>>>
> >>>> Please go ahead and apply those changes and send a new patch with
> >>>> the remainder of the changes.
> >>>
> >>> I have just pushed r12-2418:
> >>> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
> >>>
> >>>>
> >>>> A few other comments:
> >>>>
> >>>>> -                       omp_declare_simd_clauses);
> >>>>> +                       *omp_declare_simd_clauses);
> >>>>
> >>>> Instead of doing this indirection in all of the callers, let's
> >>>> change c_finish_omp_declare_simd to take a pointer as well, and do
> >>>> the indirection in initializing a reference variable at the top of
> >>>> the function.
> >>>
> >>> Okay.
> >>>
> >>>>
> >>>>> +    sched_init_luids (bbs.to_vec ());
> >>>>> +    haifa_init_h_i_d (bbs.to_vec ());
> >>>>
> >>>> Why are these to_vec changes needed when you are also changing the
> >>>> functions to take const&?
> >>>
> >>> Calling to_vec() here isn't necessary so I've removed it.
> >>>
> >>>>
> >>>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
> >>>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec
> ();
> >>>>
> >>>> Why not use a reference here and in other similar spots?
> >>>
> >>> Sure, that works too.
> >>>
> >>> Attached is what's left of the original changes now that r12-2418
> >>> has been applied.
> >>>
> >>> Martin
> >>
> >
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PING][PATCH] define auto_vec copy ctor and assignment (PR 90904)
  2021-08-06  7:52                                                         ` Christophe Lyon
@ 2021-08-06 12:17                                                           ` Christophe Lyon
  0 siblings, 0 replies; 59+ messages in thread
From: Christophe Lyon @ 2021-08-06 12:17 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Jason Merrill, Jonathan Wakely, Richard Biener, gcc-patches,
	Tamar Christina

On Fri, Aug 6, 2021 at 9:52 AM Christophe Lyon <
christophe.lyon.oss@gmail.com> wrote:

>
>
> On Fri, Aug 6, 2021 at 4:07 AM Martin Sebor via Gcc-patches <
> gcc-patches@gcc.gnu.org> wrote:
>
>> On 7/30/21 9:06 AM, Jason Merrill wrote:
>> > On 7/27/21 2:56 PM, Martin Sebor wrote:
>> >> Ping: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575690.html
>> >>
>> >> Are there any other suggestions or comments or is the latest revision
>> >> okay to commit?
>> >
>> > OK.
>>
>> I had to make a few more adjustments to fix up code that's snuck
>> in since I last tested the patch.  I committed r12-2776 after
>> retesting on x86_64-linux.
>>
>> With the cleanup out of the way I'll resubmit the copy ctor patch
>> next.
>>
>>
> Hi Martin,
>
> Your patch breaks the aarch64 build:
>  /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:
> In function 'void aarch64_sve::register_svpattern()':
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:3502:27:
> error: use of deleted function 'vec<T>::vec(auto_vec<T, N>&) [with long
> unsigned int N = 32ul;
> T = std::pair<const char*, int>]'
>         "svpattern", values);
>                            ^
> In file included from
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/hash-table.h:248:0,
>                  from
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/coretypes.h:480,
>                  from
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:24:
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/vec.h:1455:3:
> error: declared here
>    vec (auto_vec<T, N> &) = delete;
>    ^
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:
> In function 'void aarch64_sve::register_svprfop()':
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:3516:30:
> error: use of deleted function 'vec<T>::vec(auto_vec<T, N>&) [with long
> unsigned int N = 16ul;
> T = std::pair<const char*, int>]'
>              "svprfop", values);
>                               ^
> In file included from
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/hash-table.h:248:0,
>                  from
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/coretypes.h:480,
>                  from
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:24:
> /tmp/1784440_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/vec.h:1455:3:
> error: declared here
>    vec (auto_vec<T, N> &) = delete;
>    ^
>
> Can you check?
>
> Thanks,
>

This has now been fixed by Tamar, thanks!

Christophe


>
> Christophe
>
>>
>> Martin
>>
>> >
>> >> On 7/20/21 12:34 PM, Martin Sebor wrote:
>> >>> On 7/14/21 10:23 AM, Jason Merrill wrote:
>> >>>> On 7/14/21 10:46 AM, Martin Sebor wrote:
>> >>>>> On 7/13/21 9:39 PM, Jason Merrill wrote:
>> >>>>>> On 7/13/21 4:02 PM, Martin Sebor wrote:
>> >>>>>>> On 7/13/21 12:37 PM, Jason Merrill wrote:
>> >>>>>>>> On 7/13/21 10:08 AM, Jonathan Wakely wrote:
>> >>>>>>>>> On Mon, 12 Jul 2021 at 12:02, Richard Biener wrote:
>> >>>>>>>>>> Somebody with more C++ knowledge than me needs to approve the
>> >>>>>>>>>> vec.h changes - I don't feel competent to assess all effects
>> >>>>>>>>>> of the change.
>> >>>>>>>>>
>> >>>>>>>>> They look OK to me except for:
>> >>>>>>>>>
>> >>>>>>>>> -extern vnull vNULL;
>> >>>>>>>>> +static constexpr vnull vNULL{ };
>> >>>>>>>>>
>> >>>>>>>>> Making vNULL have static linkage can make it an ODR violation
>> >>>>>>>>> to use
>> >>>>>>>>> vNULL in templates and inline functions, because different
>> >>>>>>>>> instantiations will refer to a different "vNULL" in each
>> >>>>>>>>> translation
>> >>>>>>>>> unit.
>> >>>>>>>>
>> >>>>>>>> The ODR says this is OK because it's a literal constant with the
>> >>>>>>>> same value (6.2/12.2.1).
>> >>>>>>>>
>> >>>>>>>> But it would be better without the explicit 'static'; then in
>> >>>>>>>> C++17 it's implicitly inline instead of static.
>> >>>>>>>
>> >>>>>>> I'll remove the static.
>> >>>>>>>
>> >>>>>>>>
>> >>>>>>>> But then, do we really want to keep vNULL at all?  It's a weird
>> >>>>>>>> blurring of the object/pointer boundary that is also dependent
>> >>>>>>>> on vec being a thin wrapper around a pointer.  In almost all
>> >>>>>>>> cases it can be replaced with {}; one exception is ==
>> >>>>>>>> comparison, where it seems to be testing that the embedded
>> >>>>>>>> pointer is null, which is a weird thing to want to test.
>> >>>>>>>
>> >>>>>>> The one use case I know of for vNULL where I can't think of
>> >>>>>>> an equally good substitute is in passing a vec as an argument by
>> >>>>>>> value.  The only way to do that that I can think of is to name
>> >>>>>>> the full vec type (i.e., the specialization) which is more typing
>> >>>>>>> and less generic than vNULL.  I don't use vNULL myself so I
>> wouldn't
>> >>>>>>> miss this trick if it were to be removed but others might feel
>> >>>>>>> differently.
>> >>>>>>
>> >>>>>> In C++11, it can be replaced by {} in that context as well.
>> >>>>>
>> >>>>> Cool.  I thought I'd tried { } here but I guess not.
>> >>>>>
>> >>>>>>
>> >>>>>>> If not, I'm all for getting rid of vNULL but with over 350 uses
>> >>>>>>> of it left, unless there's some clever trick to make the removal
>> >>>>>>> (mostly) effortless and seamless, I'd much rather do it
>> >>>>>>> independently
>> >>>>>>> of this initial change. I also don't know if I can commit to
>> making
>> >>>>>>> all this cleanup.
>> >>>>>>
>> >>>>>> I already have a patch to replace all but one use of vNULL, but
>> >>>>>> I'll hold off with it until after your patch.
>> >>>>>
>> >>>>> So what's the next step?  The patch only removes a few uses of vNULL
>> >>>>> but doesn't add any.  Is it good to go as is (without the static and
>> >>>>> with the additional const changes Richard suggested)?  This patch is
>> >>>>> attached to my reply to Richard:
>> >>>>> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575199.html
>> >>>>
>> >>>> As Richard wrote:
>> >>>>
>> >>>>> The pieces where you change vec<> passing to const vec<>& and the
>> few
>> >>>>> where you change vec<> * to const vec<> * are OK - this should make
>> >>>>> the
>> >>>>> rest a smaller piece to review.
>> >>>>
>> >>>> Please go ahead and apply those changes and send a new patch with
>> >>>> the remainder of the changes.
>> >>>
>> >>> I have just pushed r12-2418:
>> >>> https://gcc.gnu.org/pipermail/gcc-cvs/2021-July/350886.html
>> >>>
>> >>>>
>> >>>> A few other comments:
>> >>>>
>> >>>>> -                       omp_declare_simd_clauses);
>> >>>>> +                       *omp_declare_simd_clauses);
>> >>>>
>> >>>> Instead of doing this indirection in all of the callers, let's
>> >>>> change c_finish_omp_declare_simd to take a pointer as well, and do
>> >>>> the indirection in initializing a reference variable at the top of
>> >>>> the function.
>> >>>
>> >>> Okay.
>> >>>
>> >>>>
>> >>>>> +    sched_init_luids (bbs.to_vec ());
>> >>>>> +    haifa_init_h_i_d (bbs.to_vec ());
>> >>>>
>> >>>> Why are these to_vec changes needed when you are also changing the
>> >>>> functions to take const&?
>> >>>
>> >>> Calling to_vec() here isn't necessary so I've removed it.
>> >>>
>> >>>>
>> >>>>> -  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo);
>> >>>>> +  vec<tree> checks = LOOP_VINFO_CHECK_NONZERO (loop_vinfo).to_vec
>> ();
>> >>>>
>> >>>> Why not use a reference here and in other similar spots?
>> >>>
>> >>> Sure, that works too.
>> >>>
>> >>> Attached is what's left of the original changes now that r12-2418
>> >>> has been applied.
>> >>>
>> >>> Martin
>> >>
>> >
>>
>>

^ permalink raw reply	[flat|nested] 59+ messages in thread

end of thread, other threads:[~2021-08-06 12:17 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-26 23:30 [PATCH] define auto_vec copy ctor and assignment (PR 90904) Martin Sebor
2021-04-27  7:58 ` Richard Biener
2021-04-27 13:58   ` Martin Sebor
2021-04-27 14:04     ` Richard Biener
2021-04-27 15:52       ` Martin Sebor
2021-05-03 21:50         ` [PING][PATCH] " Martin Sebor
2021-05-11 20:02           ` [PING 2][PATCH] " Martin Sebor
2021-05-27 19:33             ` [PING 3][PATCH] " Martin Sebor
2021-05-27 20:53         ` [PATCH] " Jason Merrill
2021-06-01 19:56           ` Martin Sebor
2021-06-01 21:38             ` Jason Merrill
2021-06-25 20:51               ` Martin Sebor
2021-06-25 22:11                 ` Jason Merrill
2021-06-25 22:36                   ` Martin Sebor
2021-06-28  8:07                     ` Richard Biener
2021-06-28 18:07                       ` Martin Sebor
2021-06-29 10:58                         ` Richard Biener
2021-06-29 11:34                           ` Martin Jambor
2021-06-30  1:46                           ` Martin Sebor
2021-06-30  8:48                             ` Richard Biener
2021-06-30  9:29                               ` Martin Jambor
2021-07-06 15:06                             ` [PING][PATCH] " Martin Sebor
2021-07-07  7:28                               ` Richard Biener
2021-07-07 14:37                                 ` Martin Sebor
2021-07-12 11:02                                   ` Richard Biener
2021-07-13 14:08                                     ` Jonathan Wakely
2021-07-13 18:37                                       ` Jason Merrill
2021-07-13 20:02                                         ` Martin Sebor
2021-07-14  3:39                                           ` Jason Merrill
2021-07-14 10:47                                             ` Jonathan Wakely
2021-07-14 14:46                                             ` Martin Sebor
2021-07-14 16:23                                               ` Jason Merrill
2021-07-20 18:34                                                 ` Martin Sebor
2021-07-20 20:08                                                   ` Jason Merrill
2021-07-20 21:52                                                     ` Martin Sebor
2021-07-27 18:56                                                   ` Martin Sebor
2021-07-30 15:06                                                     ` Jason Merrill
2021-08-06  2:07                                                       ` Martin Sebor
2021-08-06  7:52                                                         ` Christophe Lyon
2021-08-06 12:17                                                           ` Christophe Lyon
2021-07-14 14:44                                     ` Martin Sebor
2021-06-29 14:43                         ` [PATCH] " Jason Merrill
2021-06-29 17:18                           ` Martin Sebor
2021-06-30  8:40                             ` Richard Biener
2021-06-30  9:00                               ` Richard Sandiford
2021-06-30 12:01                                 ` Richard Biener
2021-06-28  8:05                 ` Richard Biener
2021-06-29 12:30                 ` Trevor Saunders
2021-06-02  6:55             ` Richard Biener
2021-06-02 16:04               ` Martin Sebor
2021-06-03  8:29                 ` Trevor Saunders
2021-06-07  8:51                   ` Richard Biener
2021-06-07 10:33                     ` Trevor Saunders
2021-06-07 13:33                       ` Richard Biener
2021-06-07 20:34                     ` Martin Sebor
2021-06-08  3:26                       ` Trevor Saunders
2021-06-08  7:19                         ` Richard Biener
2021-06-07 22:17                   ` Martin Sebor
2021-06-08  2:41                     ` Trevor Saunders

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).