From patchwork Thu Oct 13 21:16:25 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 119634 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E0DCFB71CF for ; Fri, 14 Oct 2011 08:16:58 +1100 (EST) Received: (qmail 17295 invoked by alias); 13 Oct 2011 21:16:53 -0000 Received: (qmail 17274 invoked by uid 22791); 13 Oct 2011 21:16:49 -0000 X-SWARE-Spam-Status: No, hits=-6.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 13 Oct 2011 21:16:27 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p9DLGRTo014497 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 13 Oct 2011 17:16:27 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p9DLGRcE022935 for ; Thu, 13 Oct 2011 17:16:27 -0400 Received: from [0.0.0.0] (ovpn-113-114.phx2.redhat.com [10.3.113.114]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p9DLGPVD007148 for ; Thu, 13 Oct 2011 17:16:26 -0400 Message-ID: <4E975529.90309@redhat.com> Date: Thu, 13 Oct 2011 17:16:25 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20111001 Thunderbird/7.0.1 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/50437 (ICE on auto with lambda in template) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org The problem here was that auto deduced the closure type of the lambda in the template, and then instantiation tried to instantiate the closure outside of the context of the LAMBDA_EXPR, which doesn't work. So I've changed LAMBDA_EXPR to always have a TREE_TYPE of NULL_TREE, and put the closure in a new field instead. Tested x86_64-pc-linux-gnu, applying to trunk. commit 1e940d8c7b567f7e0994ca99fe34b51309705d7f Author: Jason Merrill Date: Thu Oct 13 15:27:31 2011 -0400 PR c++/50437 * cp-tree.h (struct tree_lambda_expr): Add closure field. (LAMBDA_EXPR_CLOSURE): New. * pt.c (tsubst_copy_and_build) [LAMBDA_EXPR]: Likewise. * semantics.c (build_lambda_object): Use it instead of TREE_TYPE. (begin_lambda_type, lambda_function, add_capture): Likewise. (add_default_capture, lambda_expr_this_capture): Likewise. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b53accf..e42cda1 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -671,6 +671,12 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_PENDING_PROXIES(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->pending_proxies) +/* The closure type of the lambda. Note that the TREE_TYPE of a + LAMBDA_EXPR is always NULL_TREE, because we need to instantiate the + LAMBDA_EXPR in order to instantiate the type. */ +#define LAMBDA_EXPR_CLOSURE(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->closure) + struct GTY (()) tree_lambda_expr { struct tree_typed typed; @@ -678,6 +684,7 @@ struct GTY (()) tree_lambda_expr tree this_capture; tree return_type; tree extra_scope; + tree closure; VEC(tree,gc)* pending_proxies; location_t locus; enum cp_lambda_default_capture_mode_type default_capture_mode; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bfbd244..880f3d1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13937,8 +13937,8 @@ tsubst_copy_and_build (tree t, { tree r = build_lambda_expr (); - tree type = tsubst (TREE_TYPE (t), args, complain, NULL_TREE); - TREE_TYPE (r) = type; + tree type = tsubst (LAMBDA_EXPR_CLOSURE (t), args, complain, NULL_TREE); + LAMBDA_EXPR_CLOSURE (r) = type; CLASSTYPE_LAMBDA_EXPR (type) = r; LAMBDA_EXPR_LOCATION (r) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index eed38e6..7d37fa3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8324,7 +8324,7 @@ build_lambda_object (tree lambda_expr) /* N2927: "[The closure] class type is not an aggregate." But we briefly treat it as an aggregate to make this simpler. */ - type = TREE_TYPE (lambda_expr); + type = LAMBDA_EXPR_CLOSURE (lambda_expr); CLASSTYPE_NON_AGGREGATE (type) = 0; expr = finish_compound_literal (type, expr, tf_warning_or_error); CLASSTYPE_NON_AGGREGATE (type) = 1; @@ -8365,7 +8365,7 @@ begin_lambda_type (tree lambda) type = begin_class_definition (type, /*attributes=*/NULL_TREE); /* Cross-reference the expression and the type. */ - TREE_TYPE (lambda) = type; + LAMBDA_EXPR_CLOSURE (lambda) = type; CLASSTYPE_LAMBDA_EXPR (type) = lambda; return type; @@ -8399,7 +8399,7 @@ lambda_function (tree lambda) { tree type; if (TREE_CODE (lambda) == LAMBDA_EXPR) - type = TREE_TYPE (lambda); + type = LAMBDA_EXPR_CLOSURE (lambda); else type = lambda; gcc_assert (LAMBDA_TYPE_P (type)); @@ -8714,7 +8714,7 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, /* If TREE_TYPE isn't set, we're still in the introducer, so check for duplicates. */ - if (!TREE_TYPE (lambda)) + if (!LAMBDA_EXPR_CLOSURE (lambda)) { if (IDENTIFIER_MARKED (name)) { @@ -8740,13 +8740,14 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, LAMBDA_EXPR_THIS_CAPTURE (lambda) = member; /* Add it to the appropriate closure class if we've started it. */ - if (current_class_type && current_class_type == TREE_TYPE (lambda)) + if (current_class_type + && current_class_type == LAMBDA_EXPR_CLOSURE (lambda)) finish_member_declaration (member); LAMBDA_EXPR_CAPTURE_LIST (lambda) = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda)); - if (TREE_TYPE (lambda)) + if (LAMBDA_EXPR_CLOSURE (lambda)) return build_capture_proxy (member); /* For explicit captures we haven't started the function yet, so we wait and build the proxy from cp_parser_lambda_body. */ @@ -8789,7 +8790,7 @@ add_default_capture (tree lambda_stack, tree id, tree initializer) { tree lambda = TREE_VALUE (node); - current_class_type = TREE_TYPE (lambda); + current_class_type = LAMBDA_EXPR_CLOSURE (lambda); var = add_capture (lambda, id, initializer, @@ -8820,7 +8821,7 @@ lambda_expr_this_capture (tree lambda) if (!this_capture && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE) { - tree containing_function = TYPE_CONTEXT (TREE_TYPE (lambda)); + tree containing_function = TYPE_CONTEXT (LAMBDA_EXPR_CLOSURE (lambda)); tree lambda_stack = tree_cons (NULL_TREE, lambda, NULL_TREE); tree init = NULL_TREE; @@ -8870,7 +8871,8 @@ lambda_expr_this_capture (tree lambda) else { /* To make sure that current_class_ref is for the lambda. */ - gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) == TREE_TYPE (lambda)); + gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) + == LAMBDA_EXPR_CLOSURE (lambda)); result = this_capture; diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-auto1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-auto1.C new file mode 100644 index 0000000..b5ba066 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-auto1.C @@ -0,0 +1,14 @@ +// PR c++/50437 +// { dg-options -std=c++0x } + +template +void f() +{ + auto g = [](T t){ return t == 0; }; + g(T()); +} + +int main() +{ + f(); +}