PR c++/78358 - tuple decomposition decltype
authorJason Merrill <jason@redhat.com>
Tue, 15 Nov 2016 16:32:38 +0000 (11:32 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 15 Nov 2016 16:32:38 +0000 (11:32 -0500)
* semantics.c (finish_decltype_type): Strip references for a tuple
decomposition.
* cp-tree.h (DECL_DECOMPOSITION_P): False for non-variables.

From-SVN: r242432

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp1z/decomp12.C [new file with mode: 0644]

index cdac3ce..8b5fc81 100644 (file)
@@ -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.
index edcd3b4..634efc9 100644 (file)
@@ -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) \
index 29f5233..dc5ad13 100644 (file)
@@ -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 (file)
index 0000000..a5b686a
--- /dev/null
@@ -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 ();
+}