public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Movable initializer lists (C++ N4166)
@ 2015-05-03 14:48 David Krauss
  2015-05-03 15:27 ` Marc Glisse
  0 siblings, 1 reply; 4+ messages in thread
From: David Krauss @ 2015-05-03 14:48 UTC (permalink / raw)
  To: gcc-patches

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

Hi all,

A couple months ago I created a patch for movable initializer lists, as proposed in N4166. (A few additional details appeared during implementation, which I can document if anyone asks.) Reference: http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4166.pdf

As I was in the final stages of debugging and running the full testsuite, my motherboard burned out. Now I’m trying to get back into it, but the "make check" targets won’t do anything at all. This problem has happened before, and sometimes resolves itself mysteriously. I can’t do a proper clean reinstall now because Clang (I’m on OS X) won’t build GCC; it seems to be confused by C++ source files named with .c. So, everything is getting bootstrapped from a trunk version of GCC that I had sitting around. That’s probably not the problem, though; something must be wrong with DejaGnu or the makefiles.

I’m sure I’m close to the finish line, but constantly reinstalling, clean-rebuilding, and trying to diagnose tool failures seems like a waste of time and an undue strain on my laptop. I would greatly appreciate help from a more experienced contributor, or even just access to a proper build process on a fast CPU. Or even just any kind of support or compensation for my GCC efforts in general. There are several more proposals I should prototype, and I’ll be getting either a lot more involved in GCC or a lot less.

(Yes, I know that a “compile farm” exists. It appears to be obsolete; perhaps someone could vouch for it?)

The patch is missing testcases. Any contributions, review, or feedback would be appreciated. To summarize its contents:

- gcc/cp/call.c:
    build_list_conv: Allow rvalue reference tag in std::initializer_list.
    convert_like_real: Support sequence-owning std::initializer_list:
        Detect rvalue reference tag indicating ownership.
        Initialize by constructor instead of as aggregate.
        Disable static storage optimization for an owning list.
        Disable the cleanup of the array of an owning list.
        Disable the destructor of an owning list of trivial sequence.
    compare_ics: Conversion of a list to owning/non-owning std::initializer_list is preferred for nontrivial/trivial move constructor, respectively.
    set_up_extended_ref_temp: Do not build a destructor for a TARGET_EXPR with no cleanup.
    extend_ref_init_temps: Process a constructor call for std::initializer_list, not aggregate initialization.
- gcc/cp/init.c:
    perform_member_init: Process a constructor call for std::initializer_list, not aggregate initialization.
- gcc/cp/class.c:
    finish_struct: Accept new format of std::initializer_list<T&&>.
- gcc/cp/decl.c:
    cp_finish_decl: Reject owning initializer lists as nonstatic members.
- gcc/cp/typeck.c:
    check_return_expr: Reject owning initializer lists as return values.
- gcc/cp/pt.c:
    unify: Deduction of T in std::initializer_list<T&&> ignores the rvalue reference specifier.
- gcc/cp/search.c:
    accessible_p: std::initializer_list is exempt from access checking.
- gcc/cp/semantics.c:
    trait_expr_value: Owning initializer list is trivially destructible if its sequence is.
- libstdc++-v3/libsupc++/initializer_list
    class initializer_list<T>:
        Preserve internal modifiable access to sequence.
        Disable move assignment operator. (CWG DR 2432)
    class initializer_list<T&&>: New.
- gcc/testsuite/g++.dg/cpp0x/pr57101.C: Emulate new <initializer_list>.
- gcc/testsuite/g++.dg/cpp1z/initlist-owned.C: Check order of destruction functionality.
    Incomplete.
- libstdc++-v3/testsuite/20_util/is_assignable/value.cc
    Reverse availability checks on std::initializer_list value assignability.
    Add checks for owning initializer lists.
- libstdc++-v3/testsuite/util/testsuite_random.h
    Remove std::initializer_list assignment operation, and UB due to reliance on unspecified storage of temporary values.

	- Thanks,
	David



[-- Attachment #2: movil.patch --]
[-- Type: application/octet-stream, Size: 23315 bytes --]

Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 222448)
+++ gcc/cp/call.c	(working copy)
@@ -824,9 +824,16 @@ build_list_conv (tree type, tree ctor, int flags,
   /* But no narrowing conversions.  */
   flags |= LOOKUP_NO_NARROWING;
 
+  /* Rvalue references are metadata, not part of the array. */
+  if (TREE_CODE (elttype) == REFERENCE_TYPE)
+    {
+      if (cxx_dialect >= cxx1z && TYPE_REF_IS_RVALUE (elttype))
+	elttype = TREE_TYPE (elttype);
+      else
+	return NULL;
+    }
   /* Can't make an array of these types.  */
-  if (TREE_CODE (elttype) == REFERENCE_TYPE
-      || TREE_CODE (elttype) == FUNCTION_TYPE
+  if (TREE_CODE (elttype) == FUNCTION_TYPE
       || VOID_TYPE_P (elttype))
     return NULL;
 
@@ -6338,12 +6345,12 @@ convert_like_real (conversion *convs, tree expr, t
 
     case ck_list:
       {
-	/* Conversion to std::initializer_list<T>.  */
+	/* Conversion to std::initializer_list<T> or <T&&>.  */
 	tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (totype), 0);
+	bool own = TREE_CODE (elttype) == REFERENCE_TYPE;
 	tree new_ctor = build_constructor (init_list_type_node, NULL);
 	unsigned len = CONSTRUCTOR_NELTS (expr);
-	tree array, val, field;
-	vec<constructor_elt, va_gc> *vec = NULL;
+	tree array, val;
 	unsigned ix;
 
 	/* Convert all the elements.  */
@@ -6361,10 +6368,22 @@ convert_like_real (conversion *convs, tree expr, t
 	      TREE_CONSTANT (new_ctor) = false;
 	  }
 	/* Build up the array.  */
-	elttype = cp_build_qualified_type
-	  (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
-	array = build_array_of_n_type (elttype, len);
+	if (own)
+	  {
+	    elttype = TREE_TYPE (elttype);
+	    /* Don't let initializer_list<const T&&> lose ownership.  */
+	    array = cv_unqualified (elttype);
+	  }
+	else
+	  array = cp_build_qualified_type
+	    (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
+	array = build_array_of_n_type (array, len);
 	array = finish_compound_literal (array, new_ctor, complain);
+	/* If static, array is a trivially-destructible DECL, not a TARGET_EXPR.  */
+	if (own && TREE_STATIC (array)) gcc_assert (TYPE_HAS_TRIVIAL_DESTRUCTOR(elttype));
+	if (own && !TREE_STATIC (array))
+	  TARGET_EXPR_CLEANUP (array) = NULL; /* The library will handle destruction.  */
+
 	/* Take the address explicitly rather than via decay_conversion
 	   to avoid the error about taking the address of a temporary.  */
 	array = cp_build_addr_expr (array, complain);
@@ -6374,12 +6393,23 @@ convert_like_real (conversion *convs, tree expr, t
 
 	/* Build up the initializer_list object.  */
 	totype = complete_type (totype);
-	field = next_initializable_field (TYPE_FIELDS (totype));
-	CONSTRUCTOR_APPEND_ELT (vec, field, array);
-	field = next_initializable_field (DECL_CHAIN (field));
-	CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len));
-	new_ctor = build_constructor (totype, vec);
-	return get_target_expr_sfinae (new_ctor, complain);
+	
+	for (new_ctor = lookup_fnfields_slot (totype, complete_ctor_identifier);
+	     new_ctor; new_ctor = OVL_NEXT (new_ctor))
+	  {
+	    tree parm = FUNCTION_FIRST_USER_PARM (OVL_CURRENT (new_ctor));
+	    if (parm && TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
+	      break;
+	  }
+	gcc_assert (new_ctor);
+	new_ctor = OVL_CURRENT (new_ctor);
+	maybe_instantiate_noexcept (new_ctor);
+	new_ctor = build_call_n (new_ctor, 3, build_this (build_dummy_object (totype)),
+	                         array, size_int (len));
+	new_ctor = build_cplus_new (totype, new_ctor, complain);
+	if (TYPE_HAS_TRIVIAL_DESTRUCTOR (elttype))
+	  TARGET_EXPR_CLEANUP (new_ctor) = NULL; /* Trivialize destruction of the list object.  */
+	return new_ctor;
       }
 
     case ck_aggr:
@@ -8449,7 +8479,31 @@ compare_ics (conversion *ics1, conversion *ics2)
     return 1;
   if (ics2->kind == ck_list && ics1->kind != ck_list)
     return -1;
+  /* Prefer conversion to an owning or non-owning list depending on
+     availability of move semantics.  */
+  if (cxx_dialect >= cxx1z && ics1->kind == ck_list && ics2->kind == ck_list)
+    {
+      tree t1 = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (ics1->type), 0);
+      tree t2 = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (ics2->type), 0);
+      
+      if ((TREE_CODE (t1) == REFERENCE_TYPE)
+          != (TREE_CODE (t2) == REFERENCE_TYPE))
+	{
+	  bool type1_ref = TREE_CODE (t1) == REFERENCE_TYPE;
+    	  tree r = type1_ref? t1 : t2;
+    	  tree e = type1_ref? t2 : t1;
 
+    	  if (same_type_p (TREE_TYPE (r),e) && TYPE_REF_IS_RVALUE(r))
+    	    {
+	      if ((!CP_TYPE_CONST_P (e) && TYPE_HAS_COMPLEX_MOVE_CTOR (e))
+	          == type1_ref)
+	        return 1;
+	      else
+	        return -1;
+	    }
+	}
+    }
+
   /* [over.ics.rank]
 
      When  comparing  the  basic forms of implicit conversion sequences (as
@@ -9649,13 +9703,12 @@ set_up_extended_ref_temp (tree decl, tree expr, ve
     {
       add_decl_expr (var);
 
-      if (TREE_STATIC (var))
-	init = add_stmt_to_compound (init, register_dtor_fn (var));
-      else
+      if (TARGET_EXPR_CLEANUP (expr))
 	{
-	  tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
-	  if (cleanup)
-	    vec_safe_push (*cleanups, cleanup);
+	  if (TREE_STATIC (var))
+	    init = add_stmt_to_compound (init, register_dtor_fn (var));
+	  else
+	    vec_safe_push (*cleanups, build_cleanup (var));
 	}
 
       /* We must be careful to destroy the temporary only
@@ -9680,7 +9733,7 @@ set_up_extended_ref_temp (tree decl, tree expr, ve
   else
     {
       rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
-      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+      if (TARGET_EXPR_CLEANUP (expr))
 	{
 	  if (DECL_THREAD_LOCAL_P (var))
 	    tls_aggregates = tree_cons (NULL_TREE, var,
@@ -9797,23 +9850,26 @@ tree
 extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
 {
   tree type = TREE_TYPE (init);
+  tree ctor = init;
   if (processing_template_decl)
     return init;
-  if (TREE_CODE (type) == REFERENCE_TYPE)
+  if (TREE_CODE (ctor) == TARGET_EXPR)
+    ctor = TARGET_EXPR_INITIAL (ctor);
+  else if (TREE_CODE (type) == REFERENCE_TYPE)
     init = extend_ref_init_temps_1 (decl, init, cleanups);
-  else if (is_std_init_list (type))
+  if (TREE_CODE (ctor) == AGGR_INIT_EXPR && AGGR_INIT_VIA_CTOR_P (ctor)
+      && aggr_init_expr_nargs(ctor) == 3)
     {
       /* The temporary array underlying a std::initializer_list
 	 is handled like a reference temporary.  */
-      tree ctor = init;
-      if (TREE_CODE (ctor) == TARGET_EXPR)
-	ctor = TARGET_EXPR_INITIAL (ctor);
-      if (TREE_CODE (ctor) == CONSTRUCTOR)
-	{
-	  tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
+      tree il_this = AGGR_INIT_EXPR_ARG (ctor, 0);
+      if (TREE_CODE (TREE_TYPE (il_this)) == POINTER_TYPE
+          && is_std_init_list (TREE_TYPE (TREE_TYPE (il_this))))
+        {
+	  tree array = AGGR_INIT_EXPR_ARG (ctor, 1);
 	  array = extend_ref_init_temps_1 (decl, array, cleanups);
-	  CONSTRUCTOR_ELT (ctor, 0)->value = array;
-	}
+	  AGGR_INIT_EXPR_ARG (ctor, 1) = array;
+        }
     }
   else if (TREE_CODE (init) == CONSTRUCTOR)
     {
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 222448)
+++ gcc/cp/class.c	(working copy)
@@ -6883,16 +6883,23 @@ finish_struct (tree t, tree attributes)
       /* People keep complaining that the compiler crashes on an invalid
 	 definition of initializer_list, so I guess we should explicitly
 	 reject it.  What the compiler internals care about is that it's a
-	 template and has a pointer field followed by an integer field.  */
+	 template and has a pointer field followed by an integer field,
+	 or that it's derived from a preexisting initializer_list.  */
       bool ok = false;
       if (processing_template_decl)
 	{
-	  tree f = next_initializable_field (TYPE_FIELDS (t));
-	  if (f && TREE_CODE (TREE_TYPE (f)) == POINTER_TYPE)
+	  tree f = TYPE_BINFO (t);
+	  if (BINFO_N_BASE_BINFOS (f) == 1)
+	    ok = is_std_init_list (BINFO_TYPE (BINFO_BASE_BINFO (f, 0)));
+	  else
 	    {
-	      f = next_initializable_field (DECL_CHAIN (f));
-	      if (f && same_type_p (TREE_TYPE (f), size_type_node))
-		ok = true;
+	      f = next_initializable_field (TYPE_FIELDS (t));
+	      if (f && TREE_CODE (TREE_TYPE (f)) == POINTER_TYPE)
+		{
+		  f = next_initializable_field (DECL_CHAIN (f));
+		  if (f && same_type_p (TREE_TYPE (f), size_type_node))
+		    ok = true;
+		}
 	    }
 	}
       if (!ok)
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 222448)
+++ gcc/cp/decl.c	(working copy)
@@ -6655,9 +6655,17 @@ cp_finish_decl (tree decl, tree init, bool init_co
 	   so that we can decide later to emit debug info for them.  */
 	record_types_used_by_current_var_decl (decl);
     }
-  else if (TREE_CODE (decl) == FIELD_DECL
-	   && TYPE_FOR_JAVA (type) && MAYBE_CLASS_TYPE_P (type))
-    error ("non-static data member %qD has Java class type", decl);
+  else if (TREE_CODE (decl) == FIELD_DECL)
+    {
+      if (TYPE_FOR_JAVA (type) && MAYBE_CLASS_TYPE_P (type))
+	error ("non-static data member %qD has Java class type", decl);
+      if (cxx_dialect >= cxx1z && is_std_init_list (TREE_TYPE (decl)))
+	{
+	  tree il_arg = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (TREE_TYPE (decl)), 0);
+	  if (TREE_CODE (il_arg) == REFERENCE_TYPE && TYPE_REF_IS_RVALUE (il_arg))
+	    error ("non-static data member %qD cannot own an initializer list", decl);
+	}
+    }
 
   /* Add this declaration to the statement-tree.  This needs to happen
      after the call to check_initializer so that the DECL_EXPR for a
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 222448)
+++ gcc/cp/init.c	(working copy)
@@ -662,15 +662,15 @@ perform_member_init (tree member, tree init)
 	}
     }
   else if (init
-	   && (TREE_CODE (type) == REFERENCE_TYPE
+	   && (is_std_init_list (type)
+	       ||TREE_CODE (type) == REFERENCE_TYPE
 	       /* Pre-digested NSDMI.  */
 	       || (((TREE_CODE (init) == CONSTRUCTOR
 		     && TREE_TYPE (init) == type)
 		    /* { } mem-initializer.  */
 		    || (TREE_CODE (init) == TREE_LIST
 			&& DIRECT_LIST_INIT_P (TREE_VALUE (init))))
-		   && (CP_AGGREGATE_TYPE_P (type)
-		       || is_std_init_list (type)))))
+		   && CP_AGGREGATE_TYPE_P (type))))
     {
       /* With references and list-initialization, we need to deal with
 	 extending temporary lifetimes.  12.2p5: "A temporary bound to a
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 222448)
+++ gcc/cp/pt.c	(working copy)
@@ -17850,6 +17850,8 @@ unify (tree tparms, tree targs, tree parm, tree ar
       else
 	{
 	  elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
+	  if (TREE_CODE (elttype) == REFERENCE_TYPE)
+	    elttype = TREE_TYPE (elttype);
 	  /* Deduction is defined in terms of a single type, so just punt
 	     on the (bizarre) std::initializer_list<T...>.  */
 	  if (PACK_EXPANSION_P (elttype))
Index: gcc/cp/search.c
===================================================================
--- gcc/cp/search.c	(revision 222448)
+++ gcc/cp/search.c	(working copy)
@@ -935,6 +935,11 @@ accessible_p (tree type, tree decl, bool consider_
       /* Now, loop through the classes of which we are a friend.  */
       if (!protected_ok)
 	protected_ok = friend_accessible_p (scope, decl, binfo);
+
+      /* Give initializer_list a free pass to call all destructors.
+	 Actual destructor access is checked at the point of array creation.  */
+      if (!protected_ok && ct && is_std_init_list (ct))
+        return 1;
     }
 
   /* Standardize the binfo that access_in_type will use.  We don't
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 222448)
+++ gcc/cp/semantics.c	(working copy)
@@ -7477,6 +7477,15 @@ trait_expr_value (cp_trait_kind kind, tree type1,
 
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       type1 = strip_array_types (type1);
+      if (is_std_init_list (type1))
+        {
+          type1 = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (type1), 0);
+          if (TREE_CODE (type1) == REFERENCE_TYPE && TYPE_REF_IS_RVALUE (type1))
+            /* An owning initializer_list is trivially-destructible if its sequence is.  */
+            return trait_expr_value (CPTK_HAS_TRIVIAL_DESTRUCTOR, TREE_TYPE (type1), type2);
+          else
+            return true; /* Non-owning initializer lists are trivially-destructible.  */
+        }
       return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 222448)
+++ gcc/cp/typeck.c	(working copy)
@@ -8570,8 +8570,16 @@ check_return_expr (tree retval, bool *no_warning)
        value.  */
     current_function_returns_null = 1;
   else
-    /* Remember that this function did return a value.  */
-    current_function_returns_value = 1;
+    {
+      if (cxx_dialect >= cxx1z && is_std_init_list (valtype))
+        {
+          tree il_arg = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (valtype), 0);
+	  if (TREE_CODE (il_arg) == REFERENCE_TYPE && TYPE_REF_IS_RVALUE (il_arg))
+	    error ("return value of owning initializer list type %qT", valtype);
+	}
+      /* Remember that this function did return a value.  */
+      current_function_returns_value = 1;
+    }
 
   /* Check for erroneous operands -- but after giving ourselves a
      chance to provide an error about returning a value from a void
Index: gcc/testsuite/g++.dg/cpp0x/pr57101.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/pr57101.C	(revision 222448)
+++ gcc/testsuite/g++.dg/cpp0x/pr57101.C	(working copy)
@@ -174,6 +174,9 @@ namespace std
     typedef _E *iterator;
     iterator _M_array;
     size_type _M_len;
+
+    explicit initializer_list (_E *i, size_t l)
+      : _M_array(i), _M_len(l) {}
   };
   template
     <
Index: gcc/testsuite/g++.dg/cpp1z/initlist-owned.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1z/initlist-owned.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp1z/initlist-owned.C	(working copy)
@@ -0,0 +1,90 @@
+// {dg-do run}
+// {dg-options -c++1z -pedantic}
+
+#include <initializer_list>
+extern "C" void exit( int );
+template< typename t >
+t && move( t & o ) { return static_cast< t && >( o ); }
+
+#include <iostream>
+
+static unsigned long long check = 0, expect = 0;
+
+struct final_result {
+    ~final_result() {
+    	std::cout << '\n';
+        exit( check ^ expect );
+    }
+} g;
+
+struct checkpoint {
+    int n;
+    char c = '_';
+    
+    checkpoint( int inn, char inc = '_' ) : n( inn ), c( inc ) {}
+    
+    ~checkpoint() {
+        std::cout << c;
+        
+        check *= 4;
+        expect *= 4;
+        expect += n;
+    }
+};
+
+struct checkobj {
+    char c = '-';
+    
+    checkobj( char inc = '-' ) : c( inc ) {}
+    
+    ~checkobj() { std::cout << c; check += 1; }
+};
+
+#if __cplusplus > 201402
+typedef checkobj && checkobjrr;
+#else
+typedef checkobj checkobjrr;
+#endif
+
+std::initializer_list< checkobjrr > s1 { {'B'}, {'B'}, {'B'} };
+checkpoint c1 { 0, 'a' };
+
+std::initializer_list< checkobjrr > s2( move( s1 ) );
+checkpoint c2 { 3, 'b' };
+
+struct {
+    std::initializer_list< checkobjrr > && s4;
+    checkpoint c4;
+    std::initializer_list< std::initializer_list< checkobjrr > > && s5;
+    checkpoint c5;
+} cs { { {'C'}, {'C'} }, {2, 'c'}, { { {'D'}, {'D'} }, { {'D'} } }, {3, 'd'} };
+
+struct {
+    std::initializer_list< checkobjrr > && s6 = { {'Z'} };
+    checkpoint && c6 = {1, 'z'};
+} cx;
+
+void fn( std::initializer_list< checkobjrr > s, int n ) {
+    if ( n ) fn( move( s ), n - 1 );
+    checkpoint { n? 0 : (int) s.size() };
+}
+
+void fr( std::initializer_list< checkobjrr > const & ) {}
+
+void fv( std::initializer_list< checkobj > ) {}
+
+template< typename e >
+void ft( std::initializer_list< e > ) {}
+
+int main() {
+    fn( { {} }, 1 );
+    
+    std::initializer_list< checkobjrr > s7 { {}, {} };
+    checkpoint c7 { 0 };
+    
+    fr( move( s7 ) );
+    checkpoint { 0 }; // 7
+    fv( move( s7 ) );
+    checkpoint { 2 }; // 8
+    ft( move( s7 ) );
+}

Property changes on: gcc/testsuite/g++.dg/cpp1z/initlist-owned.C
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: libstdc++-v3/libsupc++/initializer_list
===================================================================
--- libstdc++-v3/libsupc++/initializer_list	(revision 222448)
+++ libstdc++-v3/libsupc++/initializer_list	(working copy)
@@ -54,18 +54,24 @@ namespace std
       typedef const _E* 	iterator;
       typedef const _E* 	const_iterator;
 
-    private:
-      iterator			_M_array;
+    protected:
+      _E*			_M_array;
       size_type			_M_len;
 
       // The compiler can call a private constructor.
-      constexpr initializer_list(const_iterator __a, size_type __l)
+      constexpr initializer_list(_E *__a, size_type __l) noexcept
       : _M_array(__a), _M_len(__l) { }
 
     public:
       constexpr initializer_list() noexcept
       : _M_array(0), _M_len(0) { }
 
+      constexpr initializer_list(initializer_list &&) noexcept = default;
+      constexpr initializer_list(const initializer_list &) noexcept = default;
+      
+      initializer_list &operator = (initializer_list &) = delete;
+      initializer_list &operator = (initializer_list &&) = delete;
+
       // Number of elements.
       constexpr size_type
       size() const noexcept { return _M_len; }
@@ -98,6 +104,87 @@ namespace std
     constexpr const _Tp*
     end(initializer_list<_Tp> __ils) noexcept
     { return __ils.end(); }
+
+#if __cplusplus > 201402
+  template<class _E>
+    class initializer_list<_E &&>
+    : public initializer_list<_E>
+    {
+    private:
+      using initializer_list<_E>::initializer_list;
+
+    public:
+      typedef _E& 		reference;
+      typedef _E*	 	iterator;
+
+      constexpr initializer_list() noexcept = default;
+
+      // This class supports moving but not copying.
+      constexpr initializer_list(initializer_list &&__o) noexcept
+      : initializer_list<_E>(__o)
+      { __o._M_len = 0; }
+
+      initializer_list(const initializer_list &) = delete;
+
+      ~initializer_list() noexcept(noexcept(iterator()->~_E()))
+      {
+	for (iterator __i = end(); __i != begin(); --__i)
+	  __i[-1].~_E();
+      }
+
+      // Add write access to the base accessor interface.
+      using initializer_list<_E>::begin;
+      
+      constexpr iterator
+      begin() noexcept { return this->_M_array; }
+
+      using initializer_list<_E>::end;
+      
+      constexpr iterator
+      end() noexcept { return begin() + this->size(); }
+    };
+
+  /**
+   *  @brief  Return an iterator pointing to the first element of
+   *          the initializer_list.
+   *  @param  __ils  Initializer list.
+   */
+  template<class _Tp>
+    constexpr _Tp*
+    begin(initializer_list<_Tp &&> &__ils) noexcept
+    { return __ils.begin(); }
+
+  template<class _Tp>
+    constexpr _Tp*
+    begin(initializer_list<_Tp &&> &&__ils) noexcept
+    { return __ils.begin(); }
+
+  template<class _Tp>
+    constexpr const _Tp*
+    begin(const initializer_list<_Tp &&> &__ils) noexcept
+    { return __ils.begin(); }
+
+  /**
+   *  @brief  Return an iterator pointing to one past the last element
+   *          of the initializer_list.
+   *  @param  __ils  Initializer list.
+   */
+  template<class _Tp>
+    constexpr _Tp*
+    end(initializer_list<_Tp &&> &__ils) noexcept
+    { return __ils.end(); }
+
+  template<class _Tp>
+    constexpr _Tp*
+    end(initializer_list<_Tp &&> &&__ils) noexcept
+    { return __ils.end(); }
+
+  template<class _Tp>
+    constexpr const _Tp*
+    end(const initializer_list<_Tp &&> &__ils) noexcept
+    { return __ils.end(); }
+#endif
+
 }
 
 #pragma GCC visibility pop
Index: libstdc++-v3/testsuite/20_util/is_assignable/value.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/is_assignable/value.cc	(revision 222448)
+++ libstdc++-v3/testsuite/20_util/is_assignable/value.cc	(working copy)
@@ -186,19 +186,34 @@ static_assert(!std::is_assignable<void*&, bool>::v
 static_assert(!std::is_assignable<E&, bool>::value, "Error");
 static_assert(!std::is_assignable<SE&, bool>::value, "Error");
 
-static_assert(std::is_assignable<std::initializer_list<int>&,
+static_assert(!std::is_assignable<std::initializer_list<int>&,
 std::initializer_list<int>>::value, "Error");
-static_assert(std::is_assignable<std::initializer_list<int>&,
+static_assert(!std::is_assignable<std::initializer_list<int>&,
 std::initializer_list<int>&&>::value, "Error");
-static_assert(std::is_assignable<std::initializer_list<int>&, const
+static_assert(!std::is_assignable<std::initializer_list<int>&, const
 std::initializer_list<int>&&>::value, "Error");
-static_assert(std::is_assignable<std::initializer_list<int>&,
+static_assert(!std::is_assignable<std::initializer_list<int>&,
 std::initializer_list<int>&>::value, "Error");
-static_assert(std::is_assignable<std::initializer_list<int>&, const
+static_assert(!std::is_assignable<std::initializer_list<int>&, const
 std::initializer_list<int>&>::value, "Error");
 static_assert(!std::is_assignable<const std::initializer_list<int>&,
 std::initializer_list<int>>::value, "Error");
 
+#if __cplusplus > 201402
+static_assert(std::is_assignable<std::initializer_list<int&&>&,
+std::initializer_list<int&&>>::value, "Error");
+static_assert(std::is_assignable<std::initializer_list<int&&>&,
+std::initializer_list<int&&>&&>::value, "Error");
+static_assert(!std::is_assignable<std::initializer_list<int&&>&, const
+std::initializer_list<int&&>&&>::value, "Error");
+static_assert(!std::is_assignable<std::initializer_list<int&&>&,
+std::initializer_list<int&&>&>::value, "Error");
+static_assert(!std::is_assignable<std::initializer_list<int&&>&, const
+std::initializer_list<int&&>&>::value, "Error");
+static_assert(!std::is_assignable<const std::initializer_list<int&&>&,
+std::initializer_list<int&&>>::value, "Error");
+#endif
+
 static_assert(!std::is_assignable<const AnyAssign&, int>::value, "Error");
 static_assert(!std::is_assignable<AnyAssign&, void>::value, "Error");
 
Index: libstdc++-v3/testsuite/util/testsuite_random.h
===================================================================
--- libstdc++-v3/testsuite/util/testsuite_random.h	(revision 222448)
+++ libstdc++-v3/testsuite/util/testsuite_random.h	(working copy)
@@ -111,10 +111,10 @@ namespace __gnu_test
 #endif
 
   inline double
-  discrete_pdf(int k, std::initializer_list<double> wl)
+  discrete_pdf(int k, std::initializer_list<double> inw)
   {
-    if (!wl.size())
-      wl = { 1.0 };
+    static std::initializer_list<double> w1 = { 1.0 };
+    std::initializer_list<double> wl = inw.size()? inw : w1;
 
     if (k < 0 || (std::size_t)k >= wl.size())
       return 0.0;

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

* Re: Movable initializer lists (C++ N4166)
  2015-05-03 14:48 Movable initializer lists (C++ N4166) David Krauss
@ 2015-05-03 15:27 ` Marc Glisse
  2015-05-03 16:00   ` David Krauss
  0 siblings, 1 reply; 4+ messages in thread
From: Marc Glisse @ 2015-05-03 15:27 UTC (permalink / raw)
  To: David Krauss; +Cc: gcc-patches

On Sun, 3 May 2015, David Krauss wrote:

> (Yes, I know that a “compile farm” exists. It appears to be obsolete; perhaps someone could vouch for it?)

What gave you that impression? It doesn't have a lot of variety, but it 
has perfectly usable x86(_64) systems, and some very impressive POWER 
ones.

-- 
Marc Glisse

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

* Re: Movable initializer lists (C++ N4166)
  2015-05-03 15:27 ` Marc Glisse
@ 2015-05-03 16:00   ` David Krauss
  2015-05-06 10:18     ` David Krauss
  0 siblings, 1 reply; 4+ messages in thread
From: David Krauss @ 2015-05-03 16:00 UTC (permalink / raw)
  To: gcc-patches


> On 2015–05–03, at 11:27 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> 
> On Sun, 3 May 2015, David Krauss wrote:
> 
>> (Yes, I know that a “compile farm” exists. It appears to be obsolete; perhaps someone could vouch for it?)
> 
> What gave you that impression? It doesn't have a lot of variety, but it has perfectly usable x86(_64) systems, and some very impressive POWER ones.

It’s hard to judge by looking at https://gcc.gnu.org/wiki/CompileFarm because newer and older machines are mixed together in the list, and some of the ones which are still powerful enough (gcc75, gcc76) are nevertheless a few years old. Maybe servers circa 2010 are still faster than my newish, 4x2-core laptop at building GCC, I can’t really estimate.

Checking the list now, it’s less confusing than it was when I last looked in February, which could also be characterized as a decrease in variety. However, this raises the question of machines being taken offline.

Besides that, are some machines overloaded? If I need to use POWER, will there be a learning curve or brittleness as on Darwin? To avoid trial and error whilst wading into the process, I’m just asking for some personal confirmation of suitability for my particular needs: same-day turnaround for clean rebuilds + testsuite validation. Too many days of my life have gone into setting up GCC builds (and then setting up again elsewhere when a problem comes up).

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

* Re: Movable initializer lists (C++ N4166)
  2015-05-03 16:00   ` David Krauss
@ 2015-05-06 10:18     ` David Krauss
  0 siblings, 0 replies; 4+ messages in thread
From: David Krauss @ 2015-05-06 10:18 UTC (permalink / raw)
  To: gcc-patches


> On 2015–05–04, at 12:00 AM, David Krauss <potswa@gmail.com> wrote:
> 
> Besides that, are some machines overloaded? If I need to use POWER, will there be a learning curve or brittleness as on Darwin? To avoid trial and error whilst wading into the process, I’m just asking for some personal confirmation of suitability for my particular needs: same-day turnaround for clean rebuilds + testsuite validation. Too many days of my life have gone into setting up GCC builds (and then setting up again elsewhere when a problem comes up).

Just to follow up: The POWER8 machine, gcc112, is a beast. Maybe it’s my time zone, but I’m getting all 152 threads to myself. No significant “background” load or other users typically hanging around. POWER does seem to have a few extra testcase failures, but no particular quirks for the uninitiated.

Glad I signed up.

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

end of thread, other threads:[~2015-05-06 10:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-03 14:48 Movable initializer lists (C++ N4166) David Krauss
2015-05-03 15:27 ` Marc Glisse
2015-05-03 16:00   ` David Krauss
2015-05-06 10:18     ` David Krauss

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).