+2011-08-23 Jason Merrill <jason@redhat.com>
+
+ Core 975
+ * decl.c (cxx_init_decl_processing): Initialize
+ dependent_lambda_return_type_node.
+ * cp-tree.h (cp_tree_index): Add CPTI_DEPENDENT_LAMBDA_RETURN_TYPE.
+ (dependent_lambda_return_type_node): Define.
+ (DECLTYPE_FOR_LAMBDA_RETURN): Remove.
+ * semantics.c (lambda_return_type): Handle overloaded function.
+ Use dependent_lambda_return_type_node instead of
+ DECLTYPE_FOR_LAMBDA_RETURN.
+ (apply_lambda_return_type): Don't check dependent_type_p.
+ * pt.c (tsubst_copy_and_build): Handle lambda return type deduction.
+ (instantiate_class_template_1): Likewise.
+ (tsubst): Don't use DECLTYPE_FOR_LAMBDA_RETURN.
+ * mangle.c (write_type): Likewise.
+ * typeck.c (structural_comptypes): Likewise.
+ (check_return_expr): Handle dependent_lambda_return_type_node.
+
2011-08-23 Jason Merrill <jason@redhat.com>
PR c++/50024
STMT_IS_FULL_EXPR_P (in _STMT)
TARGET_EXPR_LIST_INIT_P (in TARGET_EXPR)
LAMBDA_EXPR_MUTABLE_P (in LAMBDA_EXPR)
- DECLTYPE_FOR_LAMBDA_RETURN (in DECLTYPE_TYPE)
DECL_FINAL_P (in FUNCTION_DECL)
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
CPTI_CLASS_TYPE,
CPTI_UNKNOWN_TYPE,
CPTI_INIT_LIST_TYPE,
+ CPTI_DEPENDENT_LAMBDA_RETURN_TYPE,
CPTI_VTBL_TYPE,
CPTI_VTBL_PTR_TYPE,
CPTI_STD,
#define class_type_node cp_global_trees[CPTI_CLASS_TYPE]
#define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE]
#define init_list_type_node cp_global_trees[CPTI_INIT_LIST_TYPE]
+#define dependent_lambda_return_type_node cp_global_trees[CPTI_DEPENDENT_LAMBDA_RETURN_TYPE]
#define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE]
#define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE]
#define std_node cp_global_trees[CPTI_STD]
(DECLTYPE_TYPE_CHECK (NODE))->type_common.string_flag
/* These flags indicate that we want different semantics from normal
- decltype: lambda capture just drops references, lambda return also does
- type decay, lambda proxies look through implicit dereference. */
+ decltype: lambda capture just drops references, lambda proxies look
+ through implicit dereference. */
#define DECLTYPE_FOR_LAMBDA_CAPTURE(NODE) \
TREE_LANG_FLAG_0 (DECLTYPE_TYPE_CHECK (NODE))
-#define DECLTYPE_FOR_LAMBDA_RETURN(NODE) \
- TREE_LANG_FLAG_1 (DECLTYPE_TYPE_CHECK (NODE))
#define DECLTYPE_FOR_LAMBDA_PROXY(NODE) \
TREE_LANG_FLAG_2 (DECLTYPE_TYPE_CHECK (NODE))
init_list_type_node = make_node (LANG_TYPE);
record_unknown_type (init_list_type_node, "init list");
+ dependent_lambda_return_type_node = make_node (LANG_TYPE);
+ record_unknown_type (dependent_lambda_return_type_node,
+ "undeduced lambda return type");
+
{
/* Make sure we get a unique function type, so we can give
its pointer type a name. (This wins for gdb.) */
case DECLTYPE_TYPE:
/* These shouldn't make it into mangling. */
gcc_assert (!DECLTYPE_FOR_LAMBDA_CAPTURE (type)
- && !DECLTYPE_FOR_LAMBDA_RETURN (type));
+ && !DECLTYPE_FOR_LAMBDA_PROXY (type));
/* In ABI <5, we stripped decltype of a plain decl. */
if (!abi_version_at_least (5)
}
if (CLASSTYPE_LAMBDA_EXPR (type))
- maybe_add_lambda_conv_op (type);
+ {
+ tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
+ if (LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (lambda))
+ {
+ apply_lambda_return_type (lambda, void_type_node);
+ LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE;
+ }
+ instantiate_decl (lambda_function (type), false, false);
+ maybe_add_lambda_conv_op (type);
+ }
/* Set the file and line number information to whatever is given for
the class itself. This puts error messages involving generated
if (DECLTYPE_FOR_LAMBDA_CAPTURE (t))
type = lambda_capture_field_type (type);
- else if (DECLTYPE_FOR_LAMBDA_RETURN (t))
- type = lambda_return_type (type);
else if (DECLTYPE_FOR_LAMBDA_PROXY (t))
type = lambda_proxy_type (type);
else
LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
LAMBDA_EXPR_DISCRIMINATOR (r)
= (LAMBDA_EXPR_DISCRIMINATOR (t));
- LAMBDA_EXPR_CAPTURE_LIST (r)
- = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
LAMBDA_EXPR_EXTRA_SCOPE (r)
= RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
+ if (LAMBDA_EXPR_RETURN_TYPE (t) == dependent_lambda_return_type_node)
+ {
+ LAMBDA_EXPR_RETURN_TYPE (r) = dependent_lambda_return_type_node;
+ LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (r) = true;
+ }
+ else
+ LAMBDA_EXPR_RETURN_TYPE (r)
+ = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
+
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
declaration of the op() for later calls to lambda_function. */
complete_type (type);
- type = tsubst (LAMBDA_EXPR_RETURN_TYPE (t), args, complain, in_decl);
- if (type)
- apply_lambda_return_type (r, type);
+ /* The capture list refers to closure members, so this needs to
+ wait until after we finish instantiating the type. */
+ LAMBDA_EXPR_CAPTURE_LIST (r)
+ = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
return build_lambda_object (r);
}
lambda_return_type (tree expr)
{
tree type;
- if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+ if (type_unknown_p (expr)
+ || BRACE_ENCLOSED_INITIALIZER_P (expr))
{
- warning (0, "cannot deduce lambda return type from a braced-init-list");
+ cxx_incomplete_type_error (expr, TREE_TYPE (expr));
return void_type_node;
}
if (type_dependent_expression_p (expr))
- {
- type = cxx_make_type (DECLTYPE_TYPE);
- DECLTYPE_TYPE_EXPR (type) = expr;
- DECLTYPE_FOR_LAMBDA_RETURN (type) = true;
- SET_TYPE_STRUCTURAL_EQUALITY (type);
- }
+ type = dependent_lambda_return_type_node;
else
type = cv_unqualified (type_decays_to (unlowered_expr_type (expr)));
return type;
LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type;
- /* If we got a DECLTYPE_TYPE, don't stick it in the function yet,
- it would interfere with instantiating the closure type. */
- if (dependent_type_p (return_type))
- return;
if (return_type == error_mark_node)
return;
+ if (TREE_TYPE (TREE_TYPE (fco)) == return_type)
+ return;
/* TREE_TYPE (FUNCTION_DECL) == METHOD_TYPE
TREE_TYPE (METHOD_TYPE) == return-type */
/* We already have a DECL_RESULT from start_preparsed_function.
Now we need to redo the work it and allocate_struct_function
did to reflect the new type. */
+ gcc_assert (current_function_decl == fco);
result = build_decl (input_location, RESULT_DECL, NULL_TREE,
TYPE_MAIN_VARIANT (return_type));
DECL_ARTIFICIAL (result) = 1;
!= DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
|| (DECLTYPE_FOR_LAMBDA_CAPTURE (t1)
!= DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
- || (DECLTYPE_FOR_LAMBDA_RETURN (t1)
- != DECLTYPE_FOR_LAMBDA_RETURN (t2))
+ || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
+ != DECLTYPE_FOR_LAMBDA_PROXY (t2))
|| !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1),
DECLTYPE_TYPE_EXPR (t2)))
return false;
tree type = lambda_return_type (retval);
tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda);
- if (VOID_TYPE_P (type))
- { /* Nothing. */ }
- else if (oldtype == NULL_TREE)
- {
- pedwarn (input_location, OPT_pedantic, "lambda return type "
- "can only be deduced when the return statement is "
- "the only statement in the function body");
- apply_lambda_return_type (lambda, type);
- }
+ if (oldtype == NULL_TREE)
+ apply_lambda_return_type (lambda, type);
+ /* If one of the answers is type-dependent, we can't do any
+ better until instantiation time. */
+ else if (oldtype == dependent_lambda_return_type_node)
+ /* Leave it. */;
+ else if (type == dependent_lambda_return_type_node)
+ apply_lambda_return_type (lambda, type);
else if (!same_type_p (type, oldtype))
error ("inconsistent types %qT and %qT deduced for "
"lambda return type", type, oldtype);
+2011-08-23 Jason Merrill <jason@redhat.com>
+
+ Core 975
+ * g++.dg/cpp0x/lambda/lambda-deduce-ext-neg2.C: Now accepted.
+ * g++.dg/cpp0x/lambda/lambda-deduce-ext-neg.C: Adjust.
+ * g++.dg/cpp0x/lambda/lambda-deduce2.C: Test returning overload.
+ * g++.dg/cpp0x/lambda/lambda-deduce-neg.C: Remove #include.
+
2011-08-23 Jason Merrill <jason@redhat.com>
PR c++/50024
-// Testcase for an extension to allow return type deduction when the lambda
-// contains more than just a single return-statement.
+// Testcase for DR 975.
// { dg-options -std=c++0x }
bool b;
-template <class T>
-T f (T t)
-{
- return [=]
- {
- auto i = t+1;
- if (b)
- return i+1;
- else
- return i+2; // { dg-error "lambda return type" }
- }();
+struct A { int fn1(); const int& fn2(); };
+struct B { int fn1(); long fn2(); };
+
+template <class T> int f (T t) {
+ return [](T t){
+ if (b)
+ return t.fn1();
+ else
+ return t.fn2(); // { dg-error "inconsistent types" }
+ }(t);
}
int main()
{
- if (f(1) != 3)
- return 1;
+ f(A()); // { dg-bogus "" } int and const int& are compatible
+ f(B()); // { dg-message "from here" } int and long are not
}
-// Test that in pedantic mode, we warn about the extension to allow return
-// type deduction when the lambda contains more than just a single
-// return-statement.
+// Test that this is accepted even when pedantic now that it's part
+// of the standard.
// { dg-options "-std=c++0x -pedantic" }
[=] { return t+1; }; // OK
return [=] {
auto i = t+1;
- return i+1; // { dg-warning "only statement" }
+ return i+1;
}();
}
// { dg-options "-std=c++0x" }
-#include <cassert>
int main() {
int i = 0;
// PR c++/43875
// { dg-options "-std=c++0x" }
+void f();
+void f(int);
+
int main()
{
- auto x2 = []{ return { 1, 2 }; }; // { dg-message "return" }
+ auto x1 = []{ return f; }; // { dg-error "return|overloaded" }
+ auto x2 = []{ return { 1, 2 }; }; // { dg-error "return|list" }
}