Hi,

in this ICE on valid, finish_decltype_type doesn't handle a COMPOUND_EXPR when the second argument, id_expression_or_member_access_p, is true.

As analyzed by Jakub in the audit trail, at parsing time for the test involving:

   struct A3 { static const int dummy = 0; };

the *.dummy in the template argument of has_const_int_dummy is parsed as a COMPONENT_REF, but then, in case DECLTYPE_TYPE of tsubst it's turned into a COMPOUND_EXPR when it becomes clear that dummy is actually a static data member. Then id_expression_or_member_access_p == true, as stored in the DECLTYPE_TYPE, isn't correct anymore and finish_decltype_type can't handle its arguments.

Now, right before calling finish_decltype_type, we are *already* handling a case where, before the instantiation, we have ~id which, upon instantiation can turn out to be either a complement expression or a destructor: I thought we could handle in the same place this additional case of disambiguation and adjust id_expression_or_member_access_p to false in this case too. The below passes testing on x86_64-linux.

Thanks,
Paolo.

///////////////////////
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 198340)
+++ cp/pt.c     (working copy)
@@ -11781,11 +11781,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain
     case DECLTYPE_TYPE:
       {
        tree type;
+       tree expr = DECLTYPE_TYPE_EXPR (t);
 
        ++cp_unevaluated_operand;
        ++c_inhibit_evaluation_warnings;
 
-       type = tsubst_copy_and_build (DECLTYPE_TYPE_EXPR (t), args,
+       type = tsubst_copy_and_build (expr, args,
                                      complain|tf_decltype, in_decl,
                                      /*function_p*/false,
                                      /*integral_constant_expression*/false);
@@ -11801,12 +11802,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain
        else
          {
            bool id = DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t);
-           if (id && TREE_CODE (DECLTYPE_TYPE_EXPR (t)) == BIT_NOT_EXPR
-               && EXPR_P (type))
-             /* In a template ~id could be either a complement expression
-                or an unqualified-id naming a destructor; if instantiating
-                it produces an expression, it's not an id-expression or
-                member access.  */
+           /* In a template ~id could be either a complement expression
+              or an unqualified-id naming a destructor; if instantiating
+              it produces an expression, it's not an id-expression or
+              member access.  Likewise, if a COMPONENT_REF becomes upon
+              instantiation a COMPOUND_EXPR, it's actually a static data
+              member.  */
+           if (id && ((TREE_CODE (expr) == BIT_NOT_EXPR
+                       && EXPR_P (type))
+                      || (TREE_CODE (expr) == COMPONENT_REF
+                          && TREE_CODE (type) == COMPOUND_EXPR)))
              id = false;
            type = finish_decltype_type (type, id, complain);
          }
Index: testsuite/g++.dg/cpp0x/decltype52.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype52.C (revision 0)
+++ testsuite/g++.dg/cpp0x/decltype52.C (working copy)
@@ -0,0 +1,39 @@
+// PR c++/56450
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+T&& declval();
+
+template<bool, typename T = void>
+struct enable_if { };
+
+template<typename T>
+struct enable_if<true, T>
+{ typedef T type; };
+
+template<typename, typename>
+struct is_same
+{ static constexpr bool value = false; };
+
+template<typename T>
+struct is_same<T, T>
+{ static constexpr bool value = true; };
+
+template< typename, typename = void >
+struct has_const_int_dummy
+{ static constexpr bool value = false; };
+
+template< typename T >
+struct has_const_int_dummy< T, typename enable_if< is_same< decltype(
+declval< T >().dummy ), const int >::value >::type >
+{ static constexpr bool value = true; };
+
+struct A0 { const int dummy; };
+struct A1 {};
+struct A2 { int dummy(); };
+struct A3 { static const int dummy = 0; };
+
+static_assert( has_const_int_dummy< A0 >::value, "A0" );
+static_assert( !has_const_int_dummy< A1 >::value, "A1" );
+static_assert( !has_const_int_dummy< A2 >::value, "A2" );
+static_assert( !has_const_int_dummy< A3 >::value, "A3" );  // ICE

Reply via email to