Implement P0217R3 - C++17 structured bindings
authorJakub Jelinek <jakub@redhat.com>
Mon, 14 Nov 2016 05:02:58 +0000 (06:02 +0100)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 14 Nov 2016 05:02:58 +0000 (00:02 -0500)
gcc/
* match.pd: Don't try to compare addresses of variables with
DECL_VALUE_EXPR.
gcc/cp/
* cp-tree.h (struct lang_decl_base): Add decomposition_p.
(DECL_DECOMPOSITION_P): New
(enum auto_deduction_context): Add adc_decomp_type.
(enum cp_declarator_kind): Add cdk_decomp.
* constexpr.c (cxx_eval_constant_expression): Look through
DECL_VALUE_EXPR.
(potential_constant_expression_1): Likewise.
* decl.c (reshape_init): Preserve CONSTRUCTOR_IS_DIRECT_INIT.
(check_initializer): Use build_aggr_init for DECL_DECOMPOSITION_P.
(cp_finish_decl): Pass adc_decomp_type for decomposition.
(find_decomp_class_base, get_tuple_size, get_tuple_element_type)
(get_tuple_decomp_init, cp_finish_decomp): New.
(grokdeclarator): Handle decomposition.
* init.c (build_aggr_init): Handle decomposition array.
(build_vec_init): Handle initialization from { array }.
* name-lookup.c (add_function): Always wrap TEMPLATE_DECL in
OVERLOAD.
* parser.c (declarator_can_be_parameter_pack): Handle cdk_decomp.
(function_declarator_p, strip_declarator_types)
(cp_parser_check_declarator_template_parameters): Likewise.
(cp_parser_range_for, cp_convert_range_for): Handle decomposition.
(cp_parser_simple_declaration): Parse decomposition.
(cp_parser_decomposition_declaration): New.
* pt.c (tsubst_decomp_names): New.
(subst_expr) [DECL_EXPR, RANGE_FOR_STMT]: Handle decomposition.
(do_auto_deduction): Handle adc_decomp_type.
* semantics.c (finish_decltype_type): Look through DECL_VALUE_EXPR.
* typeck.c (is_bitfield_expr_with_lowered_type): Likewise.
* tree.c (lvalue_kind): Likewise.
(cp_build_reference_type): Handle reference collapsing.

Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r242377

14 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/match.pd
gcc/testsuite/g++.dg/parse/parser-pr14875-2.C

index ed44d9cecf7bf9be7d4b041560fbb918460024d1..323018240bdcc65d730404cb142cc1af31ff7f28 100644 (file)
@@ -1,3 +1,8 @@
+2016-11-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * match.pd: Don't try to compare addresses of variables with
+       DECL_VALUE_EXPR.
+
 2016-11-13  Kugan Vivekanandarajah  <kuganv@linaro.org>
 
        * ipa-cp.c (ipa_get_jf_pass_through_result): Skip unary expressions.
index daeb517452b86814bed835db7d860a989b0477cc..65574d3ee4b81016d8750b27a90c5a2c158af804 100644 (file)
@@ -1,3 +1,38 @@
+2016-11-13  Jakub Jelinek  <jakub@redhat.com>
+           Jason Merrill  <jason@redhat.com>
+
+       Implement P0217R3 - C++17 structured bindings
+       * cp-tree.h (struct lang_decl_base): Add decomposition_p.
+       (DECL_DECOMPOSITION_P): New
+       (enum auto_deduction_context): Add adc_decomp_type.
+       (enum cp_declarator_kind): Add cdk_decomp.
+       * constexpr.c (cxx_eval_constant_expression): Look through
+       DECL_VALUE_EXPR.
+       (potential_constant_expression_1): Likewise.
+       * decl.c (reshape_init): Preserve CONSTRUCTOR_IS_DIRECT_INIT.
+       (check_initializer): Use build_aggr_init for DECL_DECOMPOSITION_P.
+       (cp_finish_decl): Pass adc_decomp_type for decomposition.
+       (find_decomp_class_base, get_tuple_size, get_tuple_element_type)
+       (get_tuple_decomp_init, cp_finish_decomp): New.
+       (grokdeclarator): Handle decomposition.
+       * init.c (build_aggr_init): Handle decomposition array.
+       (build_vec_init): Handle initialization from { array }.
+       * name-lookup.c (add_function): Always wrap TEMPLATE_DECL in
+       OVERLOAD.
+       * parser.c (declarator_can_be_parameter_pack): Handle cdk_decomp.
+       (function_declarator_p, strip_declarator_types)
+       (cp_parser_check_declarator_template_parameters): Likewise.
+       (cp_parser_range_for, cp_convert_range_for): Handle decomposition.
+       (cp_parser_simple_declaration): Parse decomposition.
+       (cp_parser_decomposition_declaration): New.
+       * pt.c (tsubst_decomp_names): New.
+       (subst_expr) [DECL_EXPR, RANGE_FOR_STMT]: Handle decomposition.
+       (do_auto_deduction): Handle adc_decomp_type.
+       * semantics.c (finish_decltype_type): Look through DECL_VALUE_EXPR.
+       * typeck.c (is_bitfield_expr_with_lowered_type): Likewise.
+       * tree.c (lvalue_kind): Likewise.
+       (cp_build_reference_type): Handle reference collapsing.
+
 2016-11-13  Jason Merrill  <jason@redhat.com>
 
        * call.c (build_new_method_call_1): Include template arguments in
index 739e902cf6a1b239d00eb249e5bb8ff0c1e2bdde..e8c7702dede77a2c542ac600a20bacfd9f2d7466 100644 (file)
@@ -3770,7 +3770,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return (*ctx->values->get (t));
 
     case VAR_DECL:
-      if (is_capture_proxy (t))
+      if (DECL_HAS_VALUE_EXPR_P (t))
        return cxx_eval_constant_expression (ctx, DECL_VALUE_EXPR (t),
                                             lval, non_constant_p, overflow_p);
       /* fall through */
@@ -5037,6 +5037,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       return RECUR (TREE_OPERAND (t, 0), rval);
 
     case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (t))
+       return RECUR (DECL_VALUE_EXPR (t), rval);
       if (want_rval
          && !var_in_maybe_constexpr_fn (t)
          && !type_dependent_expression_p (t)
index 3e41a334350e8348f8966049f83091821b51b968..8c2dbe1fba6f0ab1008552d1fbe0508c17bbab16 100644 (file)
@@ -2228,7 +2228,8 @@ struct GTY(()) lang_decl_base {
   unsigned u2sel : 1;
   unsigned concept_p : 1;                  /* applies to vars and functions */
   unsigned var_declared_inline_p : 1;     /* var */
-  /* 2 spare bits */
+  unsigned decomposition_p : 1;                   /* var */
+  /* 1 spare bit */
 };
 
 /* True for DECL codes which have template info and access.  */
@@ -3626,6 +3627,16 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
   (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \
    = true)
 
+/* Nonzero if NODE is the artificial VAR_DECL for decomposition
+   declaration.  */
+#define DECL_DECOMPOSITION_P(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))                  \
+   ? DECL_LANG_SPECIFIC (NODE)->u.base.decomposition_p         \
+   : false)
+#define SET_DECL_DECOMPOSITION_P(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.decomposition_p \
+   = true)
+
 /* Nonzero if NODE is an inline VAR_DECL.  In C++17, static data members
    declared with constexpr specifier are implicitly inline variables.  */
 #define DECL_INLINE_VAR_P(NODE) \
@@ -5165,7 +5176,8 @@ enum auto_deduction_context
   adc_variable_type, /* Variable initializer deduction */
   adc_return_type,   /* Return type deduction */
   adc_unify,         /* Template argument deduction */
-  adc_requirement    /* Argument dedution constraint */
+  adc_requirement,   /* Argument deduction constraint */
+  adc_decomp_type    /* Decomposition declaration initializer deduction */
 };
 
 /* True iff this TEMPLATE_TYPE_PARM represents decltype(auto).  */
@@ -5382,6 +5394,7 @@ enum cp_declarator_kind {
   cdk_pointer,
   cdk_reference,
   cdk_ptrmem,
+  cdk_decomp,
   cdk_error
 };
 
@@ -5412,7 +5425,8 @@ struct cp_declarator {
   /* Whether we parsed an ellipsis (`...') just before the declarator,
      to indicate this is a parameter pack.  */
   BOOL_BITFIELD parameter_pack_p : 1;
-  location_t id_loc; /* Currently only set for cdk_id and cdk_function. */
+  location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
+                       cdk_function. */
   /* GNU Attributes that apply to this declarator.  If the declarator
      is a pointer or a reference, these attribute apply to the type
      pointed to.  */
@@ -5421,8 +5435,8 @@ struct cp_declarator {
      declarator is a pointer or a reference, these attributes apply
      to the pointer, rather than to the type pointed to.  */
   tree std_attributes;
-  /* For all but cdk_id and cdk_error, the contained declarator.  For
-     cdk_id and cdk_error, guaranteed to be NULL.  */
+  /* For all but cdk_id, cdk_decomp and cdk_error, the contained declarator.
+     For cdk_id, cdk_decomp and cdk_error, guaranteed to be NULL.  */
   cp_declarator *declarator;
   union {
     /* For identifiers.  */
@@ -5794,6 +5808,7 @@ extern tree start_decl                            (const cp_declarator *, cp_decl_specifier_seq *, int,
 extern void start_decl_1                       (tree, bool);
 extern bool check_array_initializer            (tree, tree, tree);
 extern void cp_finish_decl                     (tree, tree, bool, tree, int);
+extern void cp_finish_decomp                   (tree, tree, unsigned int);
 extern int cp_complete_array_type              (tree *, tree, bool);
 extern int cp_complete_array_type_or_error     (tree *, tree, bool, tsubst_flags_t);
 extern tree build_ptrmemfunc_type              (tree);
@@ -6066,7 +6081,7 @@ extern tree implicitly_declare_fn               (special_function_kind, tree,
 extern bool maybe_clone_body                   (tree);
 
 /* In parser.c */
-extern tree cp_convert_range_for (tree, tree, tree, bool);
+extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool);
 extern bool parsing_nsdmi (void);
 extern void inject_this_parameter (tree, cp_cv_quals);
 
index ccd65b104a2cd1040efdeaca6bfc870055c54372..f142c1fb9313b60bf70a47d36855e06306c2e8fd 100644 (file)
@@ -6074,6 +6074,10 @@ reshape_init (tree type, tree init, tsubst_flags_t complain)
        return error_mark_node;
     }
 
+  if (CONSTRUCTOR_IS_DIRECT_INIT (init)
+      && BRACE_ENCLOSED_INITIALIZER_P (new_init))
+    CONSTRUCTOR_IS_DIRECT_INIT (new_init) = true;
+
   return new_init;
 }
 
@@ -6254,7 +6258,8 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
       if (type == error_mark_node)
        return NULL_TREE;
 
-      if ((type_build_ctor_call (type) || CLASS_TYPE_P (type))
+      if ((type_build_ctor_call (type) || CLASS_TYPE_P (type)
+          || (DECL_DECOMPOSITION_P (decl) && TREE_CODE (type) == ARRAY_TYPE))
          && !(flags & LOOKUP_ALREADY_DIGESTED)
          && !(init && BRACE_ENCLOSED_INITIALIZER_P (init)
               && CP_AGGREGATE_TYPE_P (type)
@@ -6770,10 +6775,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
        d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
                                                  tf_warning_or_error);
       d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
-      type = TREE_TYPE (decl) = do_auto_deduction (type, d_init,
-                                                  auto_node,
-                                                   tf_warning_or_error,
-                                                   adc_variable_type);
+      enum auto_deduction_context adc = adc_variable_type;
+      if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+       adc = adc_decomp_type;
+      type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
+                                                  tf_warning_or_error, adc);
       if (type == error_mark_node)
        return;
       if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -7137,6 +7143,390 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
 }
 
+/* For class TYPE return itself or some its bases that contain
+   any direct non-static data members.  Return error_mark_node if an
+   error has been diagnosed.  */
+
+static tree
+find_decomp_class_base (location_t loc, tree type, tree ret)
+{
+  bool member_seen = false;
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+      continue;
+    else if (ret)
+      return type;
+    else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+      {
+       if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
+         error_at (loc, "cannot decompose class type %qT because it has an "
+                        "anonymous struct member", type);
+       else
+         error_at (loc, "cannot decompose class type %qT because it has an "
+                        "anonymous union member", type);
+       inform (DECL_SOURCE_LOCATION (field), "declared here");
+       return error_mark_node;
+      }
+    else if (TREE_PRIVATE (field) || TREE_PROTECTED (field))
+      {
+       error_at (loc, "cannot decompose non-public member %qD of %qT",
+                 field, type);
+       inform (DECL_SOURCE_LOCATION (field),
+               TREE_PRIVATE (field) ? "declared private here"
+               : "declared protected here");
+       return error_mark_node;
+      }
+    else
+      member_seen = true;
+
+  tree base_binfo, binfo;
+  tree orig_ret = ret;
+  int i;
+  if (member_seen)
+    ret = type;
+  for (binfo = TYPE_BINFO (type), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    {
+      tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret);
+      if (t == error_mark_node)
+       return error_mark_node;
+      if (t != NULL_TREE)
+       {
+         if (ret == type)
+           {
+             error_at (loc, "cannot decompose class type %qT: both it and "
+                            "its base class %qT have non-static data members",
+                       type, t);
+             return error_mark_node;
+           }
+         else if (orig_ret != NULL_TREE)
+           return t;
+         else if (ret == t)
+           /* OK, found the same base along another path.  We'll complain
+              in convert_to_base if it's ambiguous.  */;
+         else if (ret != NULL_TREE)
+           {
+             error_at (loc, "cannot decompose class type %qT: its base "
+                            "classes %qT and %qT have non-static data "
+                            "members", type, ret, t);
+             return error_mark_node;
+           }
+         else
+           ret = t;
+       }
+    }
+  return ret;
+}
+
+/* Return std::tuple_size<TYPE>::value.  */
+
+tree
+get_tuple_size (tree type)
+{
+  tree args = make_tree_vec (1);
+  TREE_VEC_ELT (args, 0) = type;
+  tree inst = lookup_template_class (get_identifier ("tuple_size"), args,
+                                    /*in_decl*/NULL_TREE,
+                                    /*context*/std_node,
+                                    /*entering_scope*/false, tf_none);
+  tree val = lookup_qualified_name (inst, get_identifier ("value"),
+                                   /*type*/false, /*complain*/false);
+  if (TREE_CODE (val) == VAR_DECL || TREE_CODE (val) == CONST_DECL)
+    val = maybe_constant_value (val);
+  if (TREE_CODE (val) == INTEGER_CST)
+    return val;
+  else
+    return NULL_TREE;
+}
+
+/* Return std::tuple_element<I,TYPE>::type.  */
+
+tree
+get_tuple_element_type (tree type, unsigned i)
+{
+  tree args = make_tree_vec (2);
+  TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i);
+  TREE_VEC_ELT (args, 1) = type;
+  tree inst = lookup_template_class (get_identifier ("tuple_element"), args,
+                                    /*in_decl*/NULL_TREE,
+                                    /*context*/std_node,
+                                    /*entering_scope*/false,
+                                    tf_warning_or_error);
+  return make_typename_type (inst, get_identifier ("type"),
+                            none_type, tf_warning_or_error);
+}
+
+/* Return e.get<i>() or get<i>(e).  */
+
+tree
+get_tuple_decomp_init (tree decl, unsigned i)
+{
+  tree get_id = get_identifier ("get");
+  tree targs = make_tree_vec (1);
+  TREE_VEC_ELT (targs, 0) = build_int_cst (integer_type_node, i);
+
+  tree etype = TREE_TYPE (decl);
+  tree e = convert_from_reference (decl);
+
+  /* [The id-expression] e is an lvalue if the type of the entity e is an
+     lvalue reference and an xvalue otherwise.  */
+  if (TREE_CODE (etype) != REFERENCE_TYPE
+      || TYPE_REF_IS_RVALUE (etype))
+    e = move (e);
+
+  tree fns = lookup_qualified_name (TREE_TYPE (e), get_id,
+                                   /*type*/false, /*complain*/false);
+  if (fns != error_mark_node)
+    {
+      fns = lookup_template_function (fns, targs);
+      return build_new_method_call (e, fns, /*args*/NULL,
+                                   /*path*/NULL_TREE, LOOKUP_NORMAL,
+                                   /*fn_p*/NULL, tf_warning_or_error);
+    }
+  else
+    {
+      vec<tree,va_gc> *args = make_tree_vector_single (e);
+      fns = lookup_template_function (get_id, targs);
+      fns = perform_koenig_lookup (fns, args, tf_warning_or_error);
+      return finish_call_expr (fns, &args, /*novirt*/false,
+                              /*koenig*/true, tf_warning_or_error);
+    }
+}
+
+/* Finish a decomposition declaration.  DECL is the underlying declaration
+   "e", FIRST is the head of a chain of decls for the individual identifiers
+   chained through DECL_CHAIN in reverse order and COUNT is the number of
+   those decls.  */
+
+void
+cp_finish_decomp (tree decl, tree first, unsigned int count)
+{
+  location_t loc = DECL_SOURCE_LOCATION (decl);
+  if (error_operand_p (decl))
+    {
+     error_out:
+      while (count--)
+       {
+         TREE_TYPE (first) = error_mark_node;
+         if (DECL_HAS_VALUE_EXPR_P (first))
+           {
+             SET_DECL_VALUE_EXPR (first, NULL_TREE);
+             DECL_HAS_VALUE_EXPR_P (first) = 0;
+           }
+         first = DECL_CHAIN (first);
+       }
+      return;
+    }
+
+  if (type_dependent_expression_p (decl)
+      /* This happens for range for when not in templates.
+        Still add the DECL_VALUE_EXPRs for later processing.  */
+      || (!processing_template_decl
+         && type_uses_auto (TREE_TYPE (decl))))
+    {
+      for (unsigned int i = 0; i < count; i++)
+       {
+         if (!DECL_HAS_VALUE_EXPR_P (first))
+           {
+             tree v = build_nt (ARRAY_REF, decl,
+                                size_int (count - i - 1),
+                                NULL_TREE, NULL_TREE);
+             SET_DECL_VALUE_EXPR (first, v);
+             DECL_HAS_VALUE_EXPR_P (first) = 1;
+           }
+         if (processing_template_decl)
+           {
+             retrofit_lang_decl (first);
+             SET_DECL_DECOMPOSITION_P (first);
+           }
+         first = DECL_CHAIN (first);
+       }
+      return;
+    }
+
+  auto_vec<tree, 16> v;
+  v.safe_grow (count);
+  tree d = first;
+  for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
+    {
+      v[count - i - 1] = d;
+      if (processing_template_decl)
+       {
+         retrofit_lang_decl (d);
+         SET_DECL_DECOMPOSITION_P (d);
+       }
+    }
+
+  tree type = TREE_TYPE (decl);
+  tree eltype = NULL_TREE;
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+
+  unsigned HOST_WIDE_INT eltscnt = 0;
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree nelts;
+      nelts = array_type_nelts_top (type);
+      if (nelts == error_mark_node)
+       goto error_out;
+      if (!tree_fits_uhwi_p (nelts))
+       {
+         error_at (loc, "cannot decompose variable length array %qT", type);
+         goto error_out;
+       }
+      eltscnt = tree_to_uhwi (nelts);
+      if (count != eltscnt)
+       {
+       cnt_mismatch:
+         if (count > eltscnt)
+           error_at (loc, "%u names provided while %qT decomposes into "
+                          "%wu elements", count, type, eltscnt);
+         else
+           error_at (loc, "only %u names provided while %qT decomposes into "
+                          "%wu elements", count, type, eltscnt);
+         goto error_out;
+       }
+      eltype = TREE_TYPE (type);
+      for (unsigned int i = 0; i < count; i++)
+       {
+         TREE_TYPE (v[i]) = eltype;
+         layout_decl (v[i], 0);
+         tree t = convert_from_reference (decl);
+         t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
+                         eltype, t, size_int (i), NULL_TREE,
+                         NULL_TREE);
+         SET_DECL_VALUE_EXPR (v[i], t);
+         DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+       }
+    }
+  /* 2 GNU extensions.  */
+  else if (TREE_CODE (type) == COMPLEX_TYPE)
+    {
+      eltscnt = 2;
+      if (count != eltscnt)
+       goto cnt_mismatch;
+      eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+      for (unsigned int i = 0; i < count; i++)
+       {
+         TREE_TYPE (v[i]) = eltype;
+         layout_decl (v[i], 0);
+         tree t = convert_from_reference (decl);
+         t = build1_loc (DECL_SOURCE_LOCATION (v[i]),
+                         i ? IMAGPART_EXPR : REALPART_EXPR, eltype,
+                         t);
+         SET_DECL_VALUE_EXPR (v[i], t);
+         DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+       }
+    }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      eltscnt = TYPE_VECTOR_SUBPARTS (type);
+      if (count != eltscnt)
+       goto cnt_mismatch;
+      eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+      for (unsigned int i = 0; i < count; i++)
+       {
+         TREE_TYPE (v[i]) = eltype;
+         layout_decl (v[i], 0);
+         tree t = convert_from_reference (decl);
+         convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]),
+                                                &t, size_int (i));
+         t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
+                         eltype, t, size_int (i), NULL_TREE,
+                         NULL_TREE);
+         SET_DECL_VALUE_EXPR (v[i], t);
+         DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+       }
+    }
+  else if (tree tsize = get_tuple_size (type))
+    {
+      eltscnt = tree_to_uhwi (tsize);
+      if (count != eltscnt)
+       goto cnt_mismatch;
+      for (unsigned i = 0; i < count; ++i)
+       {
+         location_t sloc = input_location;
+         location_t dloc = DECL_SOURCE_LOCATION (v[i]);
+
+         input_location = dloc;
+         tree init = get_tuple_decomp_init (decl, i);
+         tree eltype = (init == error_mark_node ? error_mark_node
+                        : get_tuple_element_type (type, i));
+         input_location = sloc;
+
+         if (init == error_mark_node || eltype == error_mark_node)
+           {
+             inform (dloc, "in initialization of decomposition variable %qD",
+                     v[i]);
+             goto error_out;
+           }
+         eltype = cp_build_reference_type (eltype, !lvalue_p (init));
+         TREE_TYPE (v[i]) = eltype;
+         layout_decl (v[i], 0);
+         if (DECL_HAS_VALUE_EXPR_P (v[i]))
+           {
+             /* In this case the names are variables, not just proxies.  */
+             SET_DECL_VALUE_EXPR (v[i], NULL_TREE);
+             DECL_HAS_VALUE_EXPR_P (v[i]) = 0;
+           }
+         cp_finish_decl (v[i], init, /*constexpr*/false,
+                         /*asm*/NULL_TREE, LOOKUP_NORMAL);
+       }
+    }
+  else if (TREE_CODE (type) == UNION_TYPE)
+    {
+      error_at (loc, "cannot decompose union type %qT", type);
+      goto error_out;
+    }
+  else if (!CLASS_TYPE_P (type))
+    {
+      error_at (loc, "cannot decompose non-array non-class type %qT", type);
+      goto error_out;
+    }
+  else
+    {
+      tree btype = find_decomp_class_base (loc, type, NULL_TREE);
+      if (btype == error_mark_node)
+       goto error_out;
+      else if (btype == NULL_TREE)
+       {
+         error_at (loc, "cannot decompose class type %qT without non-static "
+                        "data members", type);
+         goto error_out;
+       }
+      for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
+       if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+         continue;
+       else
+         eltscnt++;
+      if (count != eltscnt)
+       goto cnt_mismatch;
+      tree t = convert_from_reference (decl);
+      if (type != btype)
+       {
+         t = convert_to_base (t, btype, /*check_access*/true,
+                              /*nonnull*/false, tf_warning_or_error);
+         type = btype;
+       }
+      unsigned int i = 0;
+      for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
+       if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
+         continue;
+       else
+         {
+           tree tt = finish_non_static_data_member (field, t, NULL_TREE);
+           tree probe = tt;
+           if (REFERENCE_REF_P (probe))
+             probe = TREE_OPERAND (probe, 0);
+           TREE_TYPE (v[i]) = TREE_TYPE (probe);
+           layout_decl (v[i], 0);
+           SET_DECL_VALUE_EXPR (v[i], tt);
+           DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
+           i++;
+         }
+    }
+}
+
 /* Returns a declaration for a VAR_DECL as if:
 
      extern "C" TYPE NAME;
@@ -9449,7 +9839,7 @@ grokdeclarator (const cp_declarator *declarator,
   cp_storage_class storage_class;
   bool unsigned_p, signed_p, short_p, long_p, thread_p;
   bool type_was_error_mark_node = false;
-  bool parameter_pack_p = declarator? declarator->parameter_pack_p : false;
+  bool parameter_pack_p = declarator ? declarator->parameter_pack_p : false;
   bool template_type_arg = false;
   bool template_parm_flag = false;
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
@@ -9650,6 +10040,10 @@ grokdeclarator (const cp_declarator *declarator,
        case cdk_ptrmem:
          break;
 
+       case cdk_decomp:
+         name = "decomposition";
+         break;
+
        case cdk_error:
          return error_mark_node;
 
@@ -9859,15 +10253,15 @@ grokdeclarator (const cp_declarator *declarator,
   if (explicit_intN)
     {
       if (! int_n_enabled_p[declspecs->int_n_idx])
-       {
-         error ("%<__int%d%> is not supported by this target",
-               int_n_data[declspecs->int_n_idx].bitsize);
-         explicit_intN = false;
-       }
+       {
+         error ("%<__int%d%> is not supported by this target",
+                int_n_data[declspecs->int_n_idx].bitsize);
+         explicit_intN = false;
+       }
       else if (pedantic && ! in_system_header_at (input_location))
-       pedwarn (input_location, OPT_Wpedantic,
-                "ISO C++ does not support %<__int%d%> for %qs",
-               int_n_data[declspecs->int_n_idx].bitsize,  name);
+       pedwarn (input_location, OPT_Wpedantic,
+                "ISO C++ does not support %<__int%d%> for %qs",
+                int_n_data[declspecs->int_n_idx].bitsize, name);
     }
 
   /* Now process the modifiers that were specified
@@ -10093,6 +10487,79 @@ grokdeclarator (const cp_declarator *declarator,
       virtualp = 0;
     }
 
+  if (innermost_code == cdk_decomp)
+    {
+      location_t loc = (declarator->kind == cdk_reference
+                       ? declarator->declarator->id_loc : declarator->id_loc);
+      if (inlinep)
+       error_at (declspecs->locations[ds_inline],
+                 "decomposition declaration cannot be declared %<inline%>");
+      if (typedef_p)
+       error_at (declspecs->locations[ds_typedef],
+                 "decomposition declaration cannot be declared %<typedef%>");
+      if (constexpr_p)
+       error_at (declspecs->locations[ds_constexpr], "decomposition "
+                 "declaration cannot be declared %<constexpr%>");
+      if (thread_p)
+       error_at (declspecs->locations[ds_thread],
+                 "decomposition declaration cannot be declared %qs",
+                 declspecs->gnu_thread_keyword_p
+                 ? "__thread" : "thread_local");
+      if (concept_p)
+       error_at (declspecs->locations[ds_concept],
+                 "decomposition declaration cannot be declared %<concept%>");
+      switch (storage_class)
+       {
+       case sc_none:
+         break;
+       case sc_register:
+         error_at (loc, "decomposition declaration cannot be declared "
+                   "%<register%>");
+         break;
+       case sc_static:
+         error_at (loc, "decomposition declaration cannot be declared "
+                   "%<static%>");
+         break;
+       case sc_extern:
+         error_at (loc, "decomposition declaration cannot be declared "
+                   "%<extern%>");
+         break;
+       case sc_mutable:
+         error_at (loc, "decomposition declaration cannot be declared "
+                   "%<mutable%>");
+         break;
+       case sc_auto:
+         error_at (loc, "decomposition declaration cannot be declared "
+                   "C++98 %<auto%>");
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      if (TREE_CODE (type) != TEMPLATE_TYPE_PARM
+         || TYPE_IDENTIFIER (type) != get_identifier ("auto"))
+       {
+         if (type != error_mark_node)
+           {
+             error_at (loc, "decomposition declaration cannot be declared "
+                       "with type %qT", type);
+             inform (loc,
+                     "type must be cv-qualified %<auto%> or reference to "
+                     "cv-qualified %<auto%>");
+           }
+         type = build_qualified_type (make_auto (), type_quals);
+         declspecs->type = type;
+       }
+      inlinep = 0;
+      typedef_p = 0;
+      constexpr_p = 0;
+      thread_p = 0;
+      concept_p = 0;
+      storage_class = sc_none;
+      staticp = 0;
+      declspecs->storage_class = sc_none;
+      declspecs->locations[ds_thread] = UNKNOWN_LOCATION;
+    }
+
   /* Static anonymous unions are dealt with here.  */
   if (staticp && decl_context == TYPENAME
       && declspecs->type
@@ -10232,7 +10699,7 @@ grokdeclarator (const cp_declarator *declarator,
                                            attr_flags);
        }
 
-      if (declarator->kind == cdk_id)
+      if (declarator->kind == cdk_id || declarator->kind == cdk_decomp)
        break;
 
       inner_declarator = declarator->declarator;
@@ -10743,6 +11210,7 @@ grokdeclarator (const cp_declarator *declarator,
      is non-NULL, we know it is a cdk_id declarator; otherwise, we
      would not have exited the loop above.  */
   if (declarator
+      && declarator->kind == cdk_id
       && declarator->u.id.qualifying_scope
       && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope))
     {
@@ -10754,13 +11222,14 @@ grokdeclarator (const cp_declarator *declarator,
        {
          if (friendp)
            {
-             permerror (input_location, "member functions are implicitly friends of their class");
+             permerror (input_location, "member functions are implicitly "
+                                        "friends of their class");
              friendp = 0;
            }
          else
            permerror (declarator->id_loc, 
-                         "extra qualification %<%T::%> on member %qs",
-                         ctype, name);
+                      "extra qualification %<%T::%> on member %qs",
+                      ctype, name);
        }
       else if (/* If the qualifying type is already complete, then we
                  can skip the following checks.  */
@@ -11133,7 +11602,8 @@ grokdeclarator (const cp_declarator *declarator,
   else if (unqualified_id == NULL_TREE && decl_context != PARM
           && decl_context != CATCHPARM
           && TREE_CODE (type) != UNION_TYPE
-          && ! bitfield)
+          && ! bitfield
+          && innermost_code != cdk_decomp)
     {
       error ("abstract declarator %qT used as declaration", type);
       return error_mark_node;
@@ -11719,6 +12189,14 @@ grokdeclarator (const cp_declarator *declarator,
 
        if (inlinep)
          mark_inline_variable (decl);
+       if (innermost_code == cdk_decomp)
+         {
+           gcc_assert (declarator && declarator->kind == cdk_decomp);
+           DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
+           retrofit_lang_decl (decl);
+           DECL_ARTIFICIAL (decl) = 1;
+           SET_DECL_DECOMPOSITION_P (decl);
+         }
       }
 
     if (VAR_P (decl) && !initialized)
index 5eba4c3e18cfd12e7d84ef72c91224d8a5470428..1fad79cb247b9e06799d5398718fb6d67acd252c 100644 (file)
@@ -1575,27 +1575,34 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
 
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
-      tree itype;
+      tree itype = init ? TREE_TYPE (init) : NULL_TREE;
+      int from_array = 0;
 
-      /* An array may not be initialized use the parenthesized
-        initialization form -- unless the initializer is "()".  */
-      if (init && TREE_CODE (init) == TREE_LIST)
+      if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
+       from_array = 1;
+      else
        {
-          if (complain & tf_error)
-            error ("bad array initializer");
-         return error_mark_node;
+         /* An array may not be initialized use the parenthesized
+            initialization form -- unless the initializer is "()".  */
+         if (init && TREE_CODE (init) == TREE_LIST)
+           {
+             if (complain & tf_error)
+               error ("bad array initializer");
+             return error_mark_node;
+           }
+         /* Must arrange to initialize each element of EXP
+            from elements of INIT.  */
+         if (cv_qualified_p (type))
+           TREE_TYPE (exp) = cv_unqualified (type);
+         if (itype && cv_qualified_p (itype))
+           TREE_TYPE (init) = cv_unqualified (itype);
+         from_array = (itype && same_type_p (TREE_TYPE (init),
+                                             TREE_TYPE (exp)));
        }
-      /* Must arrange to initialize each element of EXP
-        from elements of INIT.  */
-      itype = init ? TREE_TYPE (init) : NULL_TREE;
-      if (cv_qualified_p (type))
-       TREE_TYPE (exp) = cv_unqualified (type);
-      if (itype && cv_qualified_p (itype))
-       TREE_TYPE (init) = cv_unqualified (itype);
+
       stmt_expr = build_vec_init (exp, NULL_TREE, init,
                                  /*explicit_value_init_p=*/false,
-                                 itype && same_type_p (TREE_TYPE (init),
-                                                       TREE_TYPE (exp)),
+                                 from_array,
                                   complain);
       TREE_READONLY (exp) = was_const;
       TREE_THIS_VOLATILE (exp) = was_volatile;
@@ -3891,6 +3898,18 @@ build_vec_init (tree base, tree maxindex, tree init,
   base = get_temp_regvar (ptype, rval);
   iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
 
+  bool direct_init = false;
+  if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init)
+      && CONSTRUCTOR_NELTS (init) == 1)
+    {
+      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+      if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE)
+       {
+         direct_init = DIRECT_LIST_INIT_P (init);
+         init = elt;
+       }
+    }
+
   /* If initializing one array from another, initialize element by
      element.  We rely upon the below calls to do the argument
      checking.  Evaluate the initializer before entering the try block.  */
@@ -4115,6 +4134,8 @@ build_vec_init (tree base, tree maxindex, tree init,
              from = build1 (INDIRECT_REF, itype, base2);
              if (xvalue)
                from = move (from);
+             if (direct_init)
+               from = build_tree_list (NULL_TREE, from);
            }
          else
            from = NULL_TREE;
index 172ec820b4d6700c31afdaab18575926af3f12b4..7ad65b8959905457590b0c06eb30c9c0a2e5fa0a 100644 (file)
@@ -5393,7 +5393,7 @@ add_function (struct arg_lookup *k, tree fn)
        function templates are ignored.  */;
   else if (k->fn_set && k->fn_set->add (fn))
     /* It's already in the list.  */;
-  else if (!k->functions)
+  else if (!k->functions && TREE_CODE (fn) != TEMPLATE_DECL)
     k->functions = fn;
   else if (fn == k->functions)
     ;
index e669c0d1c8a48bd29b9f3ff66308a4115f5e6dd7..9360ab0cbd69eece8ea1def1a6f23cbb65a8cfad 100644 (file)
@@ -1668,6 +1668,7 @@ declarator_can_be_parameter_pack (cp_declarator *declarator)
        {
        case cdk_id:
        case cdk_array:
+       case cdk_decomp:
          found = true;
          break;
 
@@ -1721,6 +1722,7 @@ function_declarator_p (const cp_declarator *declarator)
          && declarator->declarator->kind == cdk_id)
        return true;
       if (declarator->kind == cdk_id
+         || declarator->kind == cdk_decomp
          || declarator->kind == cdk_error)
        return false;
       declarator = declarator->declarator;
@@ -2200,6 +2202,8 @@ static void cp_parser_static_assert
   (cp_parser *, bool);
 static tree cp_parser_decltype
   (cp_parser *);
+static tree cp_parser_decomposition_declaration
+  (cp_parser *, cp_decl_specifier_seq *, tree *, location_t *);
 
 /* Declarators [gram.dcl.decl] */
 
@@ -11471,16 +11475,45 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
                     bool ivdep)
 {
   tree stmt, range_expr;
-  cxx_binding *binding = NULL;
-  tree name = NULL_TREE;
+  auto_vec <cxx_binding *, 16> bindings;
+  auto_vec <tree, 16> names;
+  tree decomp_first_name = NULL_TREE;
+  unsigned int decomp_cnt = 0;
 
   /* Get the range declaration momentarily out of the way so that
      the range expression doesn't clash with it. */
   if (range_decl != error_mark_node)
     {
-      name = DECL_NAME (range_decl);
-      binding = IDENTIFIER_BINDING (name);
-      IDENTIFIER_BINDING (name) = binding->previous;
+      if (DECL_HAS_VALUE_EXPR_P (range_decl))
+       {
+         tree v = DECL_VALUE_EXPR (range_decl);
+         /* For decomposition declaration get all of the corresponding
+            declarations out of the way.  */
+         if (TREE_CODE (v) == ARRAY_REF
+             && VAR_P (TREE_OPERAND (v, 0))
+             && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+           {
+             tree d = range_decl;
+             range_decl = TREE_OPERAND (v, 0);
+             decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+             decomp_first_name = d;
+             for (unsigned int i = 0; i < decomp_cnt; i++, d = DECL_CHAIN (d))
+               {
+                 tree name = DECL_NAME (d);
+                 names.quick_push (name);
+                 bindings.quick_push (IDENTIFIER_BINDING (name));
+                 IDENTIFIER_BINDING (name)
+                   = IDENTIFIER_BINDING (name)->previous;
+               }
+           }
+       }
+      if (names.is_empty ())
+       {
+         tree name = DECL_NAME (range_decl);
+         names.quick_push (name);
+         bindings.quick_push (IDENTIFIER_BINDING (name));
+         IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+       }
     }
 
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
@@ -11491,11 +11524,12 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
   else
     range_expr = cp_parser_expression (parser);
 
-  /* Put the range declaration back into scope. */
-  if (range_decl != error_mark_node)
+  /* Put the range declaration(s) back into scope. */
+  for (unsigned int i = 0; i < names.length (); i++)
     {
-      binding->previous = IDENTIFIER_BINDING (name);
-      IDENTIFIER_BINDING (name) = binding;
+      cxx_binding *binding = bindings[i];
+      binding->previous = IDENTIFIER_BINDING (names[i]);
+      IDENTIFIER_BINDING (names[i]) = binding;
     }
 
   /* If in template, STMT is converted to a normal for-statement
@@ -11516,7 +11550,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
   else
     {
       stmt = begin_for_stmt (scope, init);
-      stmt = cp_convert_range_for (stmt, range_decl, range_expr, ivdep);
+      stmt = cp_convert_range_for (stmt, range_decl, range_expr,
+                                  decomp_first_name, decomp_cnt, ivdep);
     }
   return stmt;
 }
@@ -11608,6 +11643,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr)
 
 tree
 cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
+                     tree decomp_first_name, unsigned int decomp_cnt,
                      bool ivdep)
 {
   tree begin, end;
@@ -11681,6 +11717,8 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
                                        tf_warning_or_error),
                  /*is_constant_init*/false, NULL_TREE,
                  LOOKUP_ONLYCONVERTING);
+  if (VAR_P (range_decl) && DECL_DECOMPOSITION_P (range_decl))
+    cp_finish_decomp (range_decl, decomp_first_name, decomp_cnt);
 
   return statement;
 }
@@ -12554,6 +12592,8 @@ cp_parser_block_declaration (cp_parser *parser,
 
    simple-declaration:
      decl-specifier-seq [opt] init-declarator-list [opt] ;
+     decl-specifier-seq ref-qualifier [opt] [ identifier-list ]
+       brace-or-equal-initializer ;
 
    init-declarator-list:
      init-declarator
@@ -12639,6 +12679,45 @@ cp_parser_simple_declaration (cp_parser* parser,
       && !cp_parser_error_occurred (parser))
     cp_parser_commit_to_tentative_parse (parser);
 
+  /* Look for C++17 decomposition declaration.  */
+  for (size_t n = 1; ; n++)
+    if (cp_lexer_nth_token_is (parser->lexer, n, CPP_AND)
+       || cp_lexer_nth_token_is (parser->lexer, n, CPP_AND_AND))
+      continue;
+    else if (cp_lexer_nth_token_is (parser->lexer, n, CPP_OPEN_SQUARE)
+            && !cp_lexer_nth_token_is (parser->lexer, n + 1, CPP_OPEN_SQUARE)
+            && decl_specifiers.any_specifiers_p)
+      {
+       tree decl
+         = cp_parser_decomposition_declaration (parser, &decl_specifiers,
+                                                maybe_range_for_decl,
+                                                &init_loc);
+
+       /* The next token should be either a `,' or a `;'.  */
+       cp_token *token = cp_lexer_peek_token (parser->lexer);
+       /* If it's a `;', we are done.  */
+       if (token->type == CPP_SEMICOLON || maybe_range_for_decl)
+         goto finish;
+       /* Anything else is an error.  */
+       else
+         {
+           /* If we have already issued an error message we don't need
+              to issue another one.  */
+           if ((decl != error_mark_node
+                && DECL_INITIAL (decl) != error_mark_node)
+               || cp_parser_uncommitted_to_tentative_parse_p (parser))
+             cp_parser_error (parser, "expected %<,%> or %<;%>");
+           /* Skip tokens until we reach the end of the statement.  */
+           cp_parser_skip_to_end_of_statement (parser);
+           /* If the next token is now a `;', consume it.  */
+           if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+             cp_lexer_consume_token (parser->lexer);
+           goto done;
+         }
+      }
+    else
+      break;
+
   tree last_type;
 
   last_type = NULL_TREE;
@@ -12791,6 +12870,7 @@ cp_parser_simple_declaration (cp_parser* parser,
     }
 
   /* Consume the `;'.  */
+ finish:
   if (!maybe_range_for_decl)
     cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
   else if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
@@ -12806,6 +12886,143 @@ cp_parser_simple_declaration (cp_parser* parser,
   pop_deferring_access_checks ();
 }
 
+/* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
+     decl-specifier-seq ref-qualifier [opt] [ identifier-list ]
+       brace-or-equal-initializer ;  */
+
+static tree
+cp_parser_decomposition_declaration (cp_parser *parser,
+                                    cp_decl_specifier_seq *decl_specifiers,
+                                    tree *maybe_range_for_decl,
+                                    location_t *init_loc)
+{
+  cp_ref_qualifier ref_qual = cp_parser_ref_qualifier_opt (parser);
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+  cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE);
+
+  /* Parse the identifier-list.  */
+  auto_vec<cp_expr, 10> v;
+  if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
+    while (true)
+      {
+       cp_expr e = cp_parser_identifier (parser);
+       if (e.get_value () == error_mark_node)
+         break;
+       v.safe_push (e);
+       if (!cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+         break;
+       cp_lexer_consume_token (parser->lexer);
+      }
+
+  location_t end_loc = cp_lexer_peek_token (parser->lexer)->location;
+  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
+    {
+      end_loc = UNKNOWN_LOCATION;
+      cp_parser_skip_to_closing_parenthesis_1 (parser, true, CPP_CLOSE_SQUARE,
+                                              false);
+      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
+       cp_lexer_consume_token (parser->lexer);
+      else
+       {
+         cp_parser_skip_to_end_of_statement (parser);
+         return error_mark_node;
+       }
+    }
+
+  if (cxx_dialect < cxx1z)
+    pedwarn (loc, 0, "decomposition declaration only available with "
+                    "-std=c++1z or -std=gnu++1z");
+
+  tree pushed_scope;
+  cp_declarator *declarator = make_declarator (cdk_decomp);
+  loc = end_loc == UNKNOWN_LOCATION ? loc : make_location (loc, loc, end_loc);
+  declarator->id_loc = loc;
+  if (ref_qual != REF_QUAL_NONE)
+    declarator = make_reference_declarator (TYPE_UNQUALIFIED, declarator,
+                                           ref_qual == REF_QUAL_RVALUE,
+                                           NULL_TREE);
+  tree decl = start_decl (declarator, decl_specifiers, SD_INITIALIZED,
+                         NULL_TREE, decl_specifiers->attributes,
+                         &pushed_scope);
+
+  unsigned int i;
+  cp_expr e;
+  cp_decl_specifier_seq decl_specs;
+  clear_decl_specs (&decl_specs);
+  decl_specs.type = make_auto ();
+  tree prev = decl;
+  FOR_EACH_VEC_ELT (v, i, e)
+    {
+      if (i == 0)
+       declarator = make_id_declarator (NULL_TREE, e.get_value (), sfk_none);
+      else
+       declarator->u.id.unqualified_name = e.get_value ();
+      declarator->id_loc = e.get_location ();
+      tree elt_pushed_scope;
+      tree decl2 = start_decl (declarator, &decl_specs, SD_INITIALIZED,
+                              NULL_TREE, NULL_TREE, &elt_pushed_scope);
+      if (decl2 == error_mark_node)
+       decl = error_mark_node;
+      else if (decl != error_mark_node && DECL_CHAIN (decl2) != prev)
+       {
+         /* Ensure we've diagnosed redeclaration if we aren't creating
+            a new VAR_DECL.  */
+         gcc_assert (errorcount);
+         decl = error_mark_node;
+       }
+      else
+       prev = decl2;
+      if (elt_pushed_scope)
+       pop_scope (elt_pushed_scope);
+    }
+
+  if (v.is_empty ())
+    {
+      error_at (loc, "empty decomposition declaration");
+      decl = error_mark_node;
+    }
+
+  if (maybe_range_for_decl == NULL
+      || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+    {
+      bool non_constant_p = false, is_direct_init = false;
+      tree initializer;
+      *init_loc = cp_lexer_peek_token (parser->lexer)->location;
+      /* Parse the initializer.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+       {
+         initializer = cp_parser_braced_list (parser, &non_constant_p);
+         CONSTRUCTOR_IS_DIRECT_INIT (initializer) = 1;
+         is_direct_init = true;
+       }
+      else
+       {
+         /* Consume the `='.  */
+         cp_parser_require (parser, CPP_EQ, RT_EQ);
+         initializer = cp_parser_initializer_clause (parser, &non_constant_p);
+       }
+
+      if (decl != error_mark_node)
+       {
+         cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
+                         is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT);
+         cp_finish_decomp (decl, prev, v.length ());
+       }
+    }
+  else if (decl != error_mark_node)
+    {
+      *maybe_range_for_decl = prev;
+      /* Ensure DECL_VALUE_EXPR is created for all the decls but
+        the underlying DECL.  */
+      cp_finish_decomp (decl, prev, v.length ());
+    }
+
+  if (pushed_scope)
+    pop_scope (pushed_scope);
+
+  return decl;
+}
+
 /* Parse a decl-specifier-seq.
 
    decl-specifier-seq:
@@ -18628,6 +18845,7 @@ strip_declarator_types (tree type, cp_declarator *declarator)
     switch (d->kind)
       {
       case cdk_id:
+      case cdk_decomp:
       case cdk_error:
        d = NULL;
        break;
@@ -25502,6 +25720,7 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser,
       return (cp_parser_check_declarator_template_parameters
              (parser, declarator->declarator, declarator_location));
 
+    case cdk_decomp:
     case cdk_error:
       return true;
 
index d9499d9284a4bc6cf2b6bc6905d673e84ca9eb2d..7eeb27ddd1cca0fff8dcb825df37884b8ddbc98d 100644 (file)
@@ -15311,6 +15311,55 @@ tsubst_find_omp_teams (tree *tp, int *walk_subtrees, void *)
   return NULL_TREE;
 }
 
+/* Helper function for tsubst_expr.  For decomposition declaration
+   artificial base DECL, which is tsubsted PATTERN_DECL, tsubst
+   also the corresponding decls representing the identifiers
+   of the decomposition declaration.  Return DECL if successful
+   or error_mark_node otherwise, set *FIRST to the first decl
+   in the list chained through DECL_CHAIN and *CNT to the number
+   of such decls.  */
+
+static tree
+tsubst_decomp_names (tree decl, tree pattern_decl, tree args,
+                    tsubst_flags_t complain, tree in_decl, tree *first,
+                    unsigned int *cnt)
+{
+  tree decl2, decl3, prev = decl;
+  *cnt = 0;
+  gcc_assert (DECL_NAME (decl) == NULL_TREE);
+  for (decl2 = DECL_CHAIN (pattern_decl);
+       decl2
+       && VAR_P (decl2)
+       && DECL_DECOMPOSITION_P (decl2)
+       && DECL_NAME (decl2);
+       decl2 = DECL_CHAIN (decl2))
+    {
+      (*cnt)++;
+      gcc_assert (DECL_HAS_VALUE_EXPR_P (decl2));
+      tree v = DECL_VALUE_EXPR (decl2);
+      DECL_HAS_VALUE_EXPR_P (decl2) = 0;
+      SET_DECL_VALUE_EXPR (decl2, NULL_TREE);
+      decl3 = tsubst (decl2, args, complain, in_decl);
+      SET_DECL_VALUE_EXPR (decl2, v);
+      DECL_HAS_VALUE_EXPR_P (decl2) = 1;
+      if (VAR_P (decl3))
+       DECL_TEMPLATE_INSTANTIATED (decl3) = 1;
+      maybe_push_decl (decl3);
+      if (error_operand_p (decl3))
+       decl = error_mark_node;
+      else if (decl != error_mark_node
+              && DECL_CHAIN (decl3) != prev)
+       {
+         gcc_assert (errorcount);
+         decl = error_mark_node;
+       }
+      else
+       prev = decl3;
+    }
+  *first = prev;
+  return decl;
+}
+
 /* Like tsubst_copy for expressions, etc. but also does semantic
    processing.  */
 
@@ -15454,6 +15503,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
                      const_init = (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P
                                    (pattern_decl));
                    cp_finish_decl (decl, init, const_init, NULL_TREE, 0);
+                   if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+                     {
+                       unsigned int cnt;
+                       tree first;
+                       decl = tsubst_decomp_names (decl, pattern_decl, args,
+                                                   complain, in_decl, &first,
+                                                   &cnt);
+                       if (decl != error_mark_node)
+                         cp_finish_decomp (decl, first, cnt);
+                     }
                  }
              }
          }
@@ -15481,7 +15540,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
         decl = tsubst (decl, args, complain, in_decl);
         maybe_push_decl (decl);
         expr = RECUR (RANGE_FOR_EXPR (t));
-        stmt = cp_convert_range_for (stmt, decl, expr, RANGE_FOR_IVDEP (t));
+       if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+         {
+           unsigned int cnt;
+           tree first;
+           decl = tsubst_decomp_names (decl, RANGE_FOR_DECL (t), args,
+                                       complain, in_decl, &first, &cnt);
+           stmt = cp_convert_range_for (stmt, decl, expr, first, cnt,
+                                        RANGE_FOR_IVDEP (t));
+         }
+       else
+         stmt = cp_convert_range_for (stmt, decl, expr, NULL_TREE, 0,
+                                      RANGE_FOR_IVDEP (t));
         RECUR (RANGE_FOR_BODY (t));
         finish_for_stmt (stmt);
       }
@@ -24800,7 +24870,15 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 
   init = resolve_nondeduced_context (init, complain);
 
-  if (AUTO_IS_DECLTYPE (auto_node))
+  if (context == adc_decomp_type
+      && auto_node == type
+      && init != error_mark_node
+      && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
+    /* [dcl.decomp]/1 - if decomposition declaration has no ref-qualifiers
+       and initializer has array type, deduce cv-qualified array type.  */
+    return cp_build_qualified_type_real (TREE_TYPE (init), TYPE_QUALS (type),
+                                        complain);
+  else if (AUTO_IS_DECLTYPE (auto_node))
     {
       bool id = (DECL_P (init)
                 || ((TREE_CODE (init) == COMPONENT_REF
@@ -24885,6 +24963,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
                     error("placeholder constraints not satisfied");
                     break;
                   case adc_variable_type:
+                 case adc_decomp_type:
                     error ("deduced initializer does not satisfy "
                            "placeholder constraints");
                     break;
@@ -24893,7 +24972,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
                            "placeholder constraints");
                     break;
                   case adc_requirement:
-                    error ("deduced expression type does not saatisy "
+                   error ("deduced expression type does not satisfy "
                            "placeholder constraints");
                     break;
                   }
index d390bf47469a45d38c30889ffcbe363e82a9c783..0164f2e5c7478a658410d5c9eedab19b12a2fe7d 100644 (file)
@@ -8873,6 +8873,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
       if (identifier_p (expr))
         expr = lookup_name (expr);
 
+      if (VAR_P (expr) && DECL_HAS_VALUE_EXPR_P (expr))
+       expr = DECL_VALUE_EXPR (expr);
+
       if (INDIRECT_REF_P (expr))
         /* This can happen when the expression is, e.g., "a.b". Just
            look at the underlying operand.  */
index 7872dd29cf82380ce37a50b9f925e69586157825..c59543768a80e28640c7339b163a34d885fd42d7 100644 (file)
@@ -142,6 +142,9 @@ lvalue_kind (const_tree ref)
        return clk_none;
       /* FALLTHRU */
     case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (ref))
+       return lvalue_kind (DECL_VALUE_EXPR (CONST_CAST_TREE (ref)));
+
       if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
          && DECL_LANG_SPECIFIC (ref)
          && DECL_IN_AGGR_P (ref))
@@ -1012,6 +1015,13 @@ tree
 cp_build_reference_type (tree to_type, bool rval)
 {
   tree lvalue_ref, t;
+
+  if (TREE_CODE (to_type) == REFERENCE_TYPE)
+    {
+      rval = rval && TYPE_REF_IS_RVALUE (to_type);
+      to_type = TREE_TYPE (to_type);
+    }
+
   lvalue_ref = build_reference_type (to_type);
   if (!rval)
     return lvalue_ref;
index 24ca1b52410b85e41b0ed65492ee9458fa48caf7..2d8b7b104406ec53e84319c283d2270283671f24 100644 (file)
@@ -1885,6 +1885,12 @@ is_bitfield_expr_with_lowered_type (const_tree exp)
        return DECL_BIT_FIELD_TYPE (field);
       }
 
+    case VAR_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (exp))
+       return is_bitfield_expr_with_lowered_type (DECL_VALUE_EXPR
+                                                  (CONST_CAST_TREE (exp)));
+      return NULL_TREE;
+
     CASE_CONVERT:
       if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)))
          == TYPE_MAIN_VARIANT (TREE_TYPE (exp)))
index 29ddcd82a1880c2d492dc26cd96d41e5b5d54ef4..79a418fa31ef77cb88dec2e7e91431d3248551d7 100644 (file)
@@ -2547,8 +2547,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (with
      {
        int equal = 2;
-       if (decl_in_symtab_p (base0)
-          && decl_in_symtab_p (base1))
+       /* Punt in GENERIC on variables with value expressions;
+         the value expressions might point to fields/elements
+         of other vars etc.  */
+       if (GENERIC
+          && ((VAR_P (base0) && DECL_HAS_VALUE_EXPR_P (base0))
+              || (VAR_P (base1) && DECL_HAS_VALUE_EXPR_P (base1))))
+        ;
+       else if (decl_in_symtab_p (base0)
+               && decl_in_symtab_p (base1))
          equal = symtab_node::get_create (base0)
                   ->equal_address_to (symtab_node::get_create (base1));
        else if ((DECL_P (base0)
index 3510aac908ff831c2123c53acf83f34c70e33e93..d2e538236bde6a1bb25c4e30492517aa4afa6c61 100644 (file)
@@ -15,7 +15,7 @@
   CHECK (xor_eq);   // { dg-error "before .xor_eq. token" }
 #undef CHECK
 #define CHECK(x)  int x
-  CHECK (<:);     // { dg-error "before .<:. token" }
+  CHECK (<:);     // { dg-error "" }
   CHECK (:>);     // { dg-error "before .:>. token" }
 #undef CHECK
 #define CHECK(x)  x