===================================================================
@@ -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");
===================================================================
@@ -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. */
===================================================================
@@ -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). */
===================================================================
@@ -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);