@@ -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)
@@ -617,14 +617,6 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
gcc_assert (EXPR_HAS_LOCATION (*expr_p));
input_location = EXPR_LOCATION (*expr_p);
- if (VAR_P (VEC_INIT_EXPR_SLOT (*expr_p))
- && DECL_DECOMPOSITION_P (VEC_INIT_EXPR_SLOT (*expr_p))
- && init
- && DIRECT_LIST_INIT_P (init)
- && CONSTRUCTOR_NELTS (init) == 1
- && (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (init, 0)->value))
- == ARRAY_TYPE))
- from_array = 1;
*expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE,
init, VEC_INIT_EXPR_VALUE_INIT (*expr_p),
from_array,
@@ -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;
}
@@ -6194,15 +6198,6 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
gcc_assert (init != NULL_TREE);
init = NULL_TREE;
}
- else if (VAR_P (decl)
- && DECL_DECOMPOSITION_P (decl)
- && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
- {
- init_code = build2 (VEC_INIT_EXPR, type, decl, init);
- TREE_SIDE_EFFECTS (init_code) = 1;
- SET_EXPR_LOCATION (init_code, DECL_SOURCE_LOCATION (decl));
- return init_code;
- }
else if (!init && DECL_REALLY_EXTERN (decl))
;
else if (init || type_build_ctor_call (type)
@@ -6263,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)
@@ -7183,7 +7179,6 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
else
member_seen = true;
- /* FIXME: How to deal with virtual bases etc.? */
tree base_binfo, binfo;
tree orig_ret = ret;
int i;
@@ -7206,6 +7201,9 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
}
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 "
@@ -7214,13 +7212,87 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
return error_mark_node;
}
else
- /* FIXME: Check if this is thru a private base? */
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
@@ -7366,6 +7438,41 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
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);
@@ -7378,10 +7485,6 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
}
else
{
- /* FIXME: try to evaluate std::tuple_size<type>::size as integral
- constant expression and use std::tuple_element<i, type> as types
- and decl.get<i> or get<i>(decl) as initializer.
- And only if that fails fall through into this. */
tree btype = find_decomp_class_base (loc, type, NULL_TREE);
if (btype == error_mark_node)
goto error_out;
@@ -7399,22 +7502,24 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
if (count != eltscnt)
goto cnt_mismatch;
tree t = convert_from_reference (decl);
- /* FIXME: need to build_base_path or something similar here. */
- gcc_assert (type == btype);
+ 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 eltype = unlowered_expr_type (field);
- /* FIXME: not really sure about the qualifiers here at all. */
- eltype = cp_build_qualified_type (eltype, TYPE_QUALS (eltype)
- | TYPE_QUALS (type));
- TREE_TYPE (v[i]) = eltype;
+ 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);
- tree tt = build3_loc (DECL_SOURCE_LOCATION (v[i]),
- COMPONENT_REF, eltype, t, field, NULL_TREE);
SET_DECL_VALUE_EXPR (v[i], tt);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
i++;
@@ -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;
@@ -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)
;
@@ -12876,9 +12876,6 @@ cp_parser_decomposition_declaration (cp_parser *parser,
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);
- if (cxx_dialect < cxx1z)
- pedwarn (loc, 0, "decomposition declaration only available with "
- "-std=c++1z or -std=gnu++1z");
/* Parse the identifier-list. */
auto_vec<cp_expr, 10> v;
@@ -12909,6 +12906,10 @@ cp_parser_decomposition_declaration (cp_parser *parser,
}
}
+ 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);
@@ -12934,8 +12935,9 @@ cp_parser_decomposition_declaration (cp_parser *parser,
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, &pushed_scope);
+ 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)
@@ -12947,6 +12949,8 @@ cp_parser_decomposition_declaration (cp_parser *parser,
}
else
prev = decl2;
+ if (elt_pushed_scope)
+ pop_scope (elt_pushed_scope);
}
if (v.is_empty ())
@@ -12990,6 +12994,9 @@ cp_parser_decomposition_declaration (cp_parser *parser,
cp_finish_decomp (decl, prev, v.length ());
}
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+
return decl;
}
@@ -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. */
@@ -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;
@@ -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)))
new file mode 100644
@@ -0,0 +1,48 @@
+// { dg-options -std=c++1z }
+
+namespace std {
+ template<typename T> struct tuple_size;
+ template<int, typename> struct tuple_element;
+}
+
+struct A1 { int i,j; } a1;
+template<> struct std::tuple_size<A1> { };
+void f1() { auto [ x ] = a1; } // { dg-error "decomposes into 2" }
+
+struct A2 { int i,j; } a2;
+template<> struct std::tuple_size<A2> { enum { value = 5 }; };
+void f2() { auto [ x ] = a2; } // { dg-error "decomposes into 5" }
+
+struct A3 { int i,j; } a3;
+template<> struct std::tuple_size<A3> { enum { value = 1 }; };
+void f3() { auto [ x ] = a3; } // { dg-error "get" }
+
+struct A3a { int i,j; int get(); } a3a;
+template<> struct std::tuple_size<A3a> { enum { value = 1 }; };
+void f3a() { auto [ x ] = a3a; } // { dg-error "get<0>" }
+
+struct A3b { int i,j; } a3b;
+int get(A3b&&);
+template<> struct std::tuple_size<A3b> { enum { value = 1 }; };
+void f3b() { auto [ x ] = a3b; } // { dg-error "get<0>" }
+
+struct A4 {
+ int ar[3];
+ template <int I> int& get() { return ar[I]; }
+} a4;
+template<> struct std::tuple_size<A4> { enum { value = 3 }; };
+template <int I>
+void f4() { auto [ x, y, z ] = a4; } // { dg-error "tuple_element" }
+
+struct A5 { } a5;
+template <int I> int& get(A5&& a);
+template<> struct std::tuple_size<A5> { enum { value = 3 }; };
+template <int I>
+void f5() { auto [ x, y, z ] = a5; } // { dg-error "tuple_element" }
+
+struct A6 { } a6;
+template <int I> int& get(A6&& a);
+template<> struct std::tuple_size<A6> { enum { value = 3 }; };
+template<> struct std::tuple_element<0, A6> { };
+template <int I>
+void f6() { auto [ x, y, z ] = a6; } // { dg-error "no type named .type" }
@@ -13,15 +13,6 @@ struct A
int a;
};
-// FIXME: without this dummy function the testcase fails to link.
-void
-fixme ()
-{
- A x1;
- A x2 = x1;
- A x3 { x1 };
-}
-
int
main ()
{
@@ -62,14 +53,13 @@ main ()
}
if (ccnt != 6 || dcnt != 12 || cccnt || tccnt != 6)
__builtin_abort ();
-#if 0
- // FIXME
+
{
A a[6];
if (ccnt != 12 || dcnt != 12 || cccnt || tccnt != 6)
__builtin_abort ();
{
- auto [b,c,d,e,f,g] { a }; // { dag-warning "decomposition declaration only available with" "" { target c++14_down } }
+ auto [b,c,d,e,f,g] { a }; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
b.a++;
@@ -80,7 +70,7 @@ main ()
if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
__builtin_abort ();
{
- auto&[ h, i, j, k, l, m ] {a}; // { dag-warning "decomposition declaration only available with" "" { target c++14_down } }
+ auto&[ h, i, j, k, l, m ] {a}; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
j.a += 4;
@@ -99,5 +89,4 @@ main ()
}
if (ccnt != 12 || dcnt != 24 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
-#endif
}
new file mode 100644
@@ -0,0 +1,47 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+namespace std {
+ template<typename T> struct tuple_size;
+ template<int, typename> struct tuple_element;
+}
+
+struct A {
+ int i;
+ template <int I> int& get() { return i; }
+};
+
+template<> struct std::tuple_size<A> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+struct B {
+ int i;
+};
+template <int I> int& get(B&& b) { return b.i; }
+template <int I> int& get(B& b) { return b.i; }
+
+template<> struct std::tuple_size<B> { static const int value = 2; };
+template<int I> struct std::tuple_element<I,B> { using type = int; };
+
+int main()
+{
+ {
+ A a = { 42 };
+ auto& [ x, y ] = a;
+ assert (&x == &y && &x == &a.i && x == 42);
+
+ auto [ x2, y2 ] = a;
+ assert (&x2 == &y2 && &x2 != &a.i && x2 == 42);
+ }
+
+ {
+ B b = { 42 };
+ auto& [ x, y ] = b;
+ assert (&x == &y && &x == &b.i && x == 42);
+
+ auto [ x2, y2 ] = b;
+ assert (&x2 == &y2 && &x2 != &b.i && x2 == 42);
+ }
+}
@@ -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