diff mbox

[RFH,/] PR 51222

Message ID 4F9BD0B8.4030005@oracle.com
State New
Headers show

Commit Message

Paolo Carlini April 28, 2012, 11:12 a.m. UTC
Hi,

On 04/28/2012 05:24 AM, Jason Merrill wrote:
> On 04/27/2012 09:42 PM, Paolo Carlini wrote:
>> In particular about the exact meaning of the FIXME? More generally, is
>> the issue here matter of compile-time optimization? Like we want to save
>> work when we actually *know* the type even in template context? (then
>> looks like type_dependent_expression_p isn't really what we want...)
> It's more of a mangling issue.  If the type is 
> instantiation-dependent, we should mangle it as written; if not, we 
> mangle the real type. Currently we don't test for 
> instantiation-dependence, so we get this wrong; your change would go 
> too far in the other direction.
Thanks for the clarification, essentially I was completely missing the 
concept of "instantiation-dependent", so far isn't used much, besides a 
block in pt.c (which I noticed just now).

In the specific case here at issue we have problems with DELETE_EXPR 
(either naked or wrapped in COMPOUND_EXPR) with NEW_EXPR as op0: the 
whole expression isn't type_dependent because DELETE_EXPR immediately 
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?

Thanks,
Paolo.

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

Comments

Jason Merrill April 29, 2012, 3:17 a.m. UTC | #1
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.

This might just be a matter of calling for_each_template_parm and 
returning 1 if we see any template parameter.

Jason
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/semantics.c
===================================================================
--- cp/semantics.c	(revision 186932)
+++ cp/semantics.c	(working copy)
@@ -5141,6 +5141,26 @@  finish_static_assert (tree condition, tree message
       input_location = saved_loc;
     }
 }
+
+static bool
+instantiation_dependent_expression_p (tree expr)
+{
+  if (!processing_template_decl)
+    return false;
+
+  if (type_dependent_expression_p (expr))
+    return true;
+
+  if (TREE_CODE (expr) == DELETE_EXPR)
+    return instantiation_dependent_expression_p (TREE_OPERAND (expr, 0));
+
+  if (TREE_CODE (expr) == COMPOUND_EXPR)
+    return (instantiation_dependent_expression_p (TREE_OPERAND (expr, 0))
+	    || instantiation_dependent_expression_p (TREE_OPERAND (expr, 1)));
+
+  return false;
+}
+
 
 /* Implements the C++0x decltype keyword. Returns the type of EXPR,
    suitable for use as a type-specifier.
@@ -5169,7 +5189,7 @@  finish_decltype_type (tree expr, bool id_expressio
     }
 
   /* 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).  */