Patchwork [C++,Patch/RFC] PR 56450

login
register
mail settings
Submitter Paolo Carlini
Date April 26, 2013, 4:59 p.m.
Message ID <517AB267.7020900@oracle.com>
Download mbox | patch
Permalink /patch/239891/
State New
Headers show

Comments

Paolo Carlini - April 26, 2013, 4:59 p.m.
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.

///////////////////////
Jason Merrill - April 27, 2013, 12:56 a.m.
Why should id_expression_or_member_access_p be false? 
"declval<T>().dummy" is a class member access (5.2.5) regardless of what 
kind of member dummy is.

Jason
Paolo Carlini - April 27, 2013, 8:07 a.m.
Hi

>Why should id_expression_or_member_access_p be false?
>"declval<T>().dummy" is a class member access (5.2.5) regardless of
>what
>kind of member dummy is.

I see, thanks. Then I suppose that finish_decltype_type must be adjusted to handle the COMPOUND_EXPR, I'll look into it.

Thanks again
Paolo

Patch

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