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