From StackOverflow (https://stackoverflow.com/q/44698195/2069064), this static assert trips: #include <type_traits> #include <tuple> int main() { auto tup = std::make_tuple(1, 2); auto [ a, b ] = tup; decltype(auto) c = a; static_assert(!std::is_reference<decltype(c)>::value, "!"); } But c should not be a reference type because decltype(a) is int.
Testcase without any headers: 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; }; template <class,class> struct same_type; template <class T> struct same_type<T,T> {}; void foo (A x) { auto [ a, b ] = x; decltype(auto) c = a; same_type<decltype(a), int>{}; same_type<decltype(c), int>{}; } In finish_decltype_type we have code to handle this: /* 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 lookup_decomp_type (expr); } But for decltype(auto) c = a; we have do_auto_deduction called with init which is *a: else if (AUTO_IS_DECLTYPE (auto_node)) { bool id = (DECL_P (init) || ((TREE_CODE (init) == COMPONENT_REF || TREE_CODE (init) == SCOPE_REF) && !REF_PARENTHESIZED_P (init))); thus id is false because init is not DECL_P and do_auto_deduction doesn't have special handling of DECL_DECOMPOSITION_P if id_expression_or_member_access_p argument is false. So, shall we for the above DECL_P (init) test test it with tree rinit = INDIRECT_REF_P (init) ? TREE_OPERAND (init, 0) : init; or something similar (what about the COMPONENT_REF/SCOPE_REF case? Shall we pass the INDIRECT_REF to finish_decltype_type if INDIRECT_REF_P (init) or not?
Seems fixed in GCC 11+.
Test added in abd7712f91c99690f8b0046ea168b2782afbac69.