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.

From-SVN: r177995
This commit is contained in:
Jason Merrill 2011-08-23 12:03:15 -04:00 committed by Jason Merrill
parent 2787914706
commit 9b8662c2b0
12 changed files with 97 additions and 58 deletions

View File

@ -1,3 +1,22 @@
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

View File

@ -83,7 +83,6 @@ c-common.h, not after.
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)
@ -775,6 +774,7 @@ enum cp_tree_index
CPTI_CLASS_TYPE,
CPTI_UNKNOWN_TYPE,
CPTI_INIT_LIST_TYPE,
CPTI_DEPENDENT_LAMBDA_RETURN_TYPE,
CPTI_VTBL_TYPE,
CPTI_VTBL_PTR_TYPE,
CPTI_STD,
@ -846,6 +846,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#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]
@ -3425,12 +3426,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
(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))

View File

@ -3597,6 +3597,10 @@ cxx_init_decl_processing (void)
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.) */

View File

@ -1953,7 +1953,7 @@ write_type (tree type)
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)

View File

@ -8887,7 +8887,16 @@ instantiate_class_template_1 (tree type)
}
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
@ -11420,8 +11429,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
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
@ -13882,10 +13889,17 @@ tsubst_copy_and_build (tree t,
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);
@ -13895,9 +13909,10 @@ tsubst_copy_and_build (tree t,
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);
}

View File

@ -8323,18 +8323,14 @@ tree
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;
@ -8394,12 +8390,10 @@ apply_lambda_return_type (tree lambda, tree 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 */
@ -8412,6 +8406,7 @@ apply_lambda_return_type (tree lambda, tree 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;

View File

@ -1331,8 +1331,8 @@ structural_comptypes (tree t1, tree t2, int strict)
!= 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;
@ -7657,15 +7657,14 @@ check_return_expr (tree retval, bool *no_warning)
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);

View File

@ -1,3 +1,11 @@
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

View File

@ -1,24 +1,22 @@
// 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
}

View File

@ -1,6 +1,5 @@
// 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" }
@ -11,7 +10,7 @@ T f (T t)
[=] { return t+1; }; // OK
return [=] {
auto i = t+1;
return i+1; // { dg-warning "only statement" }
return i+1;
}();
}

View File

@ -1,5 +1,4 @@
// { dg-options "-std=c++0x" }
#include <cassert>
int main() {
int i = 0;

View File

@ -1,7 +1,11 @@
// 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" }
}