summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/semantics.c23
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/decomp12.C20
4 files changed, 42 insertions, 10 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index cdac3ce8aa1e..8b5fc8117cf8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,10 @@
2016-11-15 Jason Merrill <jason@redhat.com>
+ PR c++/78358
+ * semantics.c (finish_decltype_type): Strip references for a tuple
+ decomposition.
+ * cp-tree.h (DECL_DECOMPOSITION_P): False for non-variables.
+
* decl2.c (decl_maybe_constant_var_p): References qualify.
* constexpr.c (non_const_var_error): Handle references.
* init.c (constant_value_1): Always check decl_constant_var_p.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index edcd3b47fa87..634efc9ba5c5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3627,10 +3627,10 @@ 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
+/* Nonzero if NODE is an artificial VAR_DECL for a C++17 decomposition
declaration. */
#define DECL_DECOMPOSITION_P(NODE) \
- (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \
+ (VAR_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
? DECL_LANG_SPECIFIC (NODE)->u.base.decomposition_p \
: false)
#define SET_DECL_DECOMPOSITION_P(NODE) \
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 29f52333a94c..dc5ad13f681c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8873,14 +8873,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
if (identifier_p (expr))
expr = lookup_name (expr);
- /* The decltype rules for decomposition are different from the rules for
- member access; in particular, the decomposition decl gets
- cv-qualifiers from the aggregate object, whereas decltype of a member
- access expr ignores the object. */
- if (VAR_P (expr) && DECL_DECOMPOSITION_P (expr)
- && DECL_HAS_VALUE_EXPR_P (expr))
- return unlowered_expr_type (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. */
@@ -8898,6 +8890,21 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
/* See through BASELINK nodes to the underlying function. */
expr = BASELINK_FUNCTIONS (expr);
+ /* decltype of a decomposition name drops references in the tuple case
+ (unlike decltype of a normal variable) and keeps cv-qualifiers from
+ the containing object in the other cases (unlike decltype of a member
+ access expression). */
+ if (DECL_DECOMPOSITION_P (expr))
+ {
+ if (DECL_HAS_VALUE_EXPR_P (expr))
+ /* Expr is an array or struct subobject proxy, handle
+ bit-fields properly. */
+ return unlowered_expr_type (expr);
+ else
+ /* Expr is a reference variable for the tuple case. */
+ return non_reference (TREE_TYPE (expr));
+ }
+
switch (TREE_CODE (expr))
{
case FIELD_DECL:
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp12.C b/gcc/testsuite/g++.dg/cpp1z/decomp12.C
new file mode 100644
index 000000000000..a5b686abdf92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp12.C
@@ -0,0 +1,20 @@
+// PR c++/78358
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+#include <tuple>
+
+template <typename, typename> struct same_type;
+template <typename T> struct same_type<T, T> {};
+
+int main() {
+ std::tuple tuple = { 1, 'a', 2.3, true };
+ auto[i, c, d, b] = tuple;
+ same_type<std::tuple_element<0, decltype(tuple)>::type, decltype(i)>{};
+ same_type<decltype(i), int>{};
+ same_type<decltype(c), char>{};
+ same_type<decltype(d), double>{};
+ same_type<decltype(b), bool>{};
+ if (i != 1 || c != 'a' || d != 2.3 || b != true)
+ __builtin_abort ();
+}