diff mbox

[RFH,/] PR 51222

Message ID 4F9D6180.4030408@oracle.com
State New
Headers show

Commit Message

Paolo Carlini April 29, 2012, 3:42 p.m. UTC
Hi,

On 04/29/2012 05:17 AM, Jason Merrill wrote:
> On 04/28/2012 07:12 AM, Paolo Carlini wrote:
>> isn't, but clearly can be instantiation dependent. Then, I guess the way
>> I'm proposing to handle this is by starting some sort of embryonic
>> instantiation_dependent_expression_p and using it only here, for now,
>> like the attached (which passes on x86_64-linux). What do you think?
>
> I think that implementing it properly shouldn't be that much harder; 
> the definition from the ABI is
>
> An expression is instantiation-dependent if it is type-dependent or 
> value-dependent, or it has a subexpression that is type-dependent or 
> value-dependent.
Ok, yesterday didn't read it, sorry.
> This might just be a matter of calling for_each_template_parm and 
> returning 1 if we see any template parameter.
Good. Today I quickly tried something along these lines (see 'p' 
attachment) and got some fails:

FAIL: g++.dg/abi/mangle45.C scan-assembler _Z1fIiEvT_DtfL0p_E
FAIL: g++.dg/abi/mangle45.C scan-assembler _Z1gIiEvT_PFDtfL0p_EvE
FAIL: g++.dg/abi/mangle49.C scan-assembler _Z2f1I1SENDtfp_E4typeET_
FAIL: g++.dg/cpp0x/decltype21.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae12.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae17.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae21.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae28.C (test for excess errors)
FAIL: g++.dg/cpp0x/trailing1.C scan-assembler _Z1lIiEDtfp_ET_
FAIL: g++.dg/cpp0x/variadic121.C (test for excess errors)

I don't know if you believe it could be easily amended (*)...

Otherwise, I'm attaching something very close to the letter of the ABI, 
which passes as-is the testsuite. If you like, I could also exercise 
more this version of instantiation_dependent_expression_p by changing 
static_assert too to also use it.

Thanks,
Paolo.

(*) In case somebody is curious, include_nondeduced_p doesn't change 
anything.

/////////////////////////

Index: pt.c
===================================================================
--- pt.c	(revision 186943)
+++ pt.c	(working copy)
@@ -19742,6 +19742,33 @@ type_dependent_expression_p (tree expression)
   return (dependent_type_p (TREE_TYPE (expression)));
 }
 
+static int
+template_parm_p (tree t ATTRIBUTE_UNUSED, void* data ATTRIBUTE_UNUSED)
+{ return 1; }
+
+/* Returns TRUE if the EXPRESSION is instantiation-dependent, in the
+   sense defined by the ABI:
+
+   "An expression is instantiation-dependent if it is type-dependent
+   or value-dependent, or it has a subexpression that is type-dependent
+   or value-dependent."  */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+  if (!processing_template_decl)
+    return false;
+
+  if (expression == error_mark_node)
+    return false;
+
+  if (!TREE_TYPE (expression))
+    return true;
+
+  return for_each_template_parm (expression, template_parm_p, NULL, NULL,
+				 /*include_nondeduced_p=*/true);
+}
+
 /* Like type_dependent_expression_p, but it also works while not processing
    a template definition, i.e. during substitution or mangling.  */
 
Index: semantics.c
===================================================================
--- semantics.c	(revision 186943)
+++ semantics.c	(working copy)
@@ -5168,8 +5168,7 @@ finish_decltype_type (tree expr, bool id_expressio
       return error_mark_node;
     }
 
-  /* FIXME instantiation-dependent  */
-  if (type_dependent_expression_p (expr)
+  if (instantiation_dependent_expression_p (expr)
       /* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even
 	 if it isn't dependent, so that we can check access control at
 	 instantiation time, so defer the decltype as well (PR 42277).  */
Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 186943)
+++ cp-tree.h	(working copy)
@@ -5363,6 +5363,7 @@ extern bool any_type_dependent_arguments_p      (c
 extern bool any_type_dependent_elements_p       (const_tree);
 extern bool type_dependent_expression_p_push	(tree);
 extern bool value_dependent_expression_p	(tree);
+extern bool instantiation_dependent_expression_p(tree);
 extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);

Comments

Paolo Carlini April 29, 2012, 4:57 p.m. UTC | #1
On 04/29/2012 05:42 PM, Paolo Carlini wrote:
> Otherwise, I'm attaching something very close to the letter of the 
> ABI, which passes as-is the testsuite.
Which in any case should use cp_tree_operand_length.

Paolo.
Jason Merrill April 30, 2012, 5:04 p.m. UTC | #2
On 04/29/2012 11:42 AM, Paolo Carlini wrote:
>> This might just be a matter of calling for_each_template_parm and
>> returning 1 if we see any template parameter.
> Good. Today I quickly tried something along these lines (see 'p'
> attachment) and got some fails:

Ah, well.  I guess for_each_template_parm doesn't look at the types of 
declarations.

> Otherwise, I'm attaching something very close to the letter of the ABI,

Your patch only looks at immediate subexpressions; I believe what the 
ABI means is any subexpression, which is why I think something involving 
walk_tree might be the way to go.

Jason
Paolo Carlini April 30, 2012, 5:28 p.m. UTC | #3
Hi,

> Your patch only looks at immediate subexpressions; I believe what the ABI means is any subexpression, which is why I think something involving walk_tree might be the way to go.

Ok, I'm going to open code something using walk_tree and quite similar to for_each_template_parm but checking also TREE_TYPE, let's if it's enough at least to avoid the regressions.
> 

Thanks,
Paolo
Paolo Carlini April 30, 2012, 9:18 p.m. UTC | #4
Hi again,

On 04/30/2012 07:04 PM, Jason Merrill wrote:
> On 04/29/2012 11:42 AM, Paolo Carlini wrote:
>>> This might just be a matter of calling for_each_template_parm and
>>> returning 1 if we see any template parameter.
>> Good. Today I quickly tried something along these lines (see 'p'
>> attachment) and got some fails:
>
> Ah, well.  I guess for_each_template_parm doesn't look at the types of 
> declarations.
Just wanted to add that I just confirmed that *at least* the following 
testcases, regressing with the elementary for_each_template_parm patch:

FAIL: g++.dg/cpp0x/decltype21.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae17.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae21.C (test for excess errors)
FAIL: g++.dg/cpp0x/sfinae28.C (test for excess errors)

are characterized by expr with TREE_CODE (expr) == CONSTRUCTOR and 
TREE_TYPE (expr) == TEMPLATE_TYPE_PARM.

Paolo.
diff mbox

Patch

Index: testsuite/g++.dg/cpp0x/decltype37.C
===================================================================
--- testsuite/g++.dg/cpp0x/decltype37.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/decltype37.C	(revision 0)
@@ -0,0 +1,101 @@ 
+// PR c++/51222
+// { dg-options -std=c++11 }
+
+template<class T>
+struct add_rref {
+  typedef T&& type;
+};
+
+template<>
+struct add_rref<void> {
+  typedef void type;
+};
+
+template<class T>
+typename add_rref<T>::type declval();
+
+template<class T, class U, class =
+  decltype(::delete ::new T(declval<U>()))
+>
+auto f(int) -> char;
+
+template<class, class>
+auto f(...) -> char(&)[2];
+
+template<class T, class =
+  decltype(::delete ::new T())
+>
+auto g(int) -> char;
+
+template<class>
+auto g(...) -> char(&)[2];
+
+template<class T, class U>
+auto f2(int) -> decltype(::delete ::new T(declval<U>()), char());
+
+template<class, class>
+auto f2(...) -> char(&)[2];
+
+template<class T>
+auto g2(int) -> decltype(::delete ::new T(), char());
+
+template<class>
+auto g2(...) -> char(&)[2];
+
+struct C { };
+
+struct A {
+  virtual ~A() = 0;
+};
+
+struct D1 {
+  D1() = delete;
+};
+
+struct D2 {
+  ~D2() = delete;
+};
+
+static_assert(sizeof(g<void>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void()>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(g<A>(0)) == 2, "Ouch");
+static_assert(sizeof(g<D1>(0)) == 2, "Ouch");
+static_assert(sizeof(g<D2>(0)) == 2, "Ouch");
+static_assert(sizeof(g<int&>(0)) == 2, "Ouch");
+static_assert(sizeof(g<int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void(&&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(), void()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void() const, void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f<C, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<C, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int&, int&>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int&&, int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(&)(), void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(&&)(), void(&&)()>(0)) == 2, "Ouch");
+
+static_assert(sizeof(g2<void>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void()>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<A>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<D1>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<D2>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<int&>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void(&&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(), void()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void() const, void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<C, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<C, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int&, int&>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int&&, int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(&)(), void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(&&)(), void(&&)()>(0)) == 2, "Ouch");
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 186943)
+++ cp/pt.c	(working copy)
@@ -19742,6 +19742,36 @@  type_dependent_expression_p (tree expression)
   return (dependent_type_p (TREE_TYPE (expression)));
 }
 
+/* Returns TRUE if the EXPRESSION is instantiation-dependent, in the
+   sense defined by the ABI:
+
+   "An expression is instantiation-dependent if it is type-dependent
+   or value-dependent, or it has a subexpression that is type-dependent
+   or value-dependent."  */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+  int i, n;
+
+  if (!processing_template_decl)
+    return false;
+
+  if (type_dependent_expression_p (expression)
+      || value_dependent_expression_p (expression))
+    return true;
+
+  n = TREE_OPERAND_LENGTH (expression);
+  for (i = 0; i < n; i++)
+    {
+      tree op = TREE_OPERAND (expression, i);
+      if (op && instantiation_dependent_expression_p (op))
+	return true;
+    }
+
+  return false;
+}
+
 /* Like type_dependent_expression_p, but it also works while not processing
    a template definition, i.e. during substitution or mangling.  */
 
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 186943)
+++ cp/semantics.c	(working copy)
@@ -5168,8 +5168,7 @@  finish_decltype_type (tree expr, bool id_expressio
       return error_mark_node;
     }
 
-  /* FIXME instantiation-dependent  */
-  if (type_dependent_expression_p (expr)
+  if (instantiation_dependent_expression_p (expr)
       /* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even
 	 if it isn't dependent, so that we can check access control at
 	 instantiation time, so defer the decltype as well (PR 42277).  */
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 186943)
+++ cp/cp-tree.h	(working copy)
@@ -5363,6 +5363,7 @@  extern bool any_type_dependent_arguments_p      (c
 extern bool any_type_dependent_elements_p       (const_tree);
 extern bool type_dependent_expression_p_push	(tree);
 extern bool value_dependent_expression_p	(tree);
+extern bool instantiation_dependent_expression_p(tree);
 extern bool any_value_dependent_elements_p      (const_tree);
 extern bool dependent_omp_for_p			(tree, tree, tree, tree);
 extern tree resolve_typename_type		(tree, bool);