diff mbox

C++ PATCH for c++/78358 (decltype and decomposition)

Message ID CADzB+2kCyFEU2EL9v83u4UjQC+JD3=onBd9qyheQnn9HFFUqcA@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Nov. 15, 2016, 4:31 p.m. UTC
OK, (hopefully) one more patch for decltype and C++17 decomposition
declarations.  I hadn't been thinking that "referenced type" meant to
look through references in the tuple case, since other parts of
[dcl.decomp] define "the referenced type" directly, but that does seem
to be how it's used elsewhere in the standard.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 113051a8a3e231bb4003831a2f595cd8788eec64
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Nov 15 10:50:00 2016 -0500

            PR c++/78358 - tuple decomposition decltype
    
            * semantics.c (finish_decltype_type): Strip references for a tuple
            decomposition.
            * cp-tree.h (DECL_DECOMPOSITION_P): False for non-variables.
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index edcd3b4..634efc9 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 29f5233..dc5ad13 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 0000000..a5b686a
--- /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 ();
+}