From patchwork Wed Jun 29 17:24:41 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 102644 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 160D8B6F59 for ; Thu, 30 Jun 2011 03:25:01 +1000 (EST) Received: (qmail 4665 invoked by alias); 29 Jun 2011 17:24:59 -0000 Received: (qmail 4653 invoked by uid 22791); 29 Jun 2011 17:24:57 -0000 X-SWARE-Spam-Status: No, hits=-6.3 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_CX, T_RP_MATCHES_RCVD 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; Wed, 29 Jun 2011 17:24:42 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p5THOfNn015166 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 29 Jun 2011 13:24:41 -0400 Received: from [127.0.0.1] (ovpn-113-39.phx2.redhat.com [10.3.113.39]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p5THOf3i015584 for ; Wed, 29 Jun 2011 13:24:41 -0400 Message-ID: <4E0B5FD9.7090002@redhat.com> Date: Wed, 29 Jun 2011 13:24:41 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b2 Thunderbird/3.1.10 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/49554 (bogus error 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 failure in this testcase was happening because we were trying to evaluate the capture decltype again when instantiating the lambda operator(), but it only works when we're still in the enclosing function context. Fixed by basically waiting to copy the type over at instantiation time rather than copy the dependent type at template definition time. Tested x86_64-pc-linux-gnu, applied to trunk. commit 7493431b3a7c540254aa92cd0e8ea873eace94f8 Author: Jason Merrill Date: Wed Jun 29 11:55:58 2011 -0400 PR c++/49554 * semantics.c (lambda_proxy_type): New. (build_capture_proxy): Use it. * cp-tree.h (DECLTYPE_FOR_LAMBDA_PROXY): New. * pt.c (tsubst) [DECLTYPE_TYPE]: Use them. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7244cc8..55c88e3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3418,11 +3418,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* These flags indicate that we want different semantics from normal decltype: lambda capture just drops references, lambda return also does - type decay. */ + type decay, 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)) /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was specified in its declaration. This can also be set for an @@ -5455,6 +5457,7 @@ extern tree build_lambda_object (tree); extern tree begin_lambda_type (tree); extern tree lambda_capture_field_type (tree); extern tree lambda_return_type (tree); +extern tree lambda_proxy_type (tree); extern tree lambda_function (tree); extern void apply_lambda_return_type (tree, tree); extern tree add_capture (tree, tree, tree, bool, bool); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b3dd85f..d1d8336 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11108,6 +11108,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) 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 type = finish_decltype_type (type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t), complain); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4581729..fb984d4 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8489,6 +8489,27 @@ insert_pending_capture_proxies (void) LAMBDA_EXPR_PENDING_PROXIES (lam) = NULL; } +/* Given REF, a COMPONENT_REF designating a field in the lambda closure, + return the type we want the proxy to have: the type of the field itself, + with added const-qualification if the lambda isn't mutable and the + capture is by value. */ + +tree +lambda_proxy_type (tree ref) +{ + tree type; + if (REFERENCE_REF_P (ref)) + ref = TREE_OPERAND (ref, 0); + type = TREE_TYPE (ref); + if (!dependent_type_p (type)) + return type; + type = cxx_make_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (type) = ref; + DECLTYPE_FOR_LAMBDA_PROXY (type) = true; + SET_TYPE_STRUCTURAL_EQUALITY (type); + return type; +} + /* MEMBER is a capture field in a lambda closure class. Now that we're inside the operator(), build a placeholder var for future lookups and debugging. */ @@ -8496,7 +8517,7 @@ insert_pending_capture_proxies (void) tree build_capture_proxy (tree member) { - tree var, object, fn, closure, name, lam; + tree var, object, fn, closure, name, lam, type; closure = DECL_CONTEXT (member); fn = lambda_function (closure); @@ -8511,7 +8532,8 @@ build_capture_proxy (tree member) /* Remove the __ inserted by add_capture. */ name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); - var = build_decl (input_location, VAR_DECL, name, TREE_TYPE (object)); + type = lambda_proxy_type (object); + var = build_decl (input_location, VAR_DECL, name, type); SET_DECL_VALUE_EXPR (var, object); DECL_HAS_VALUE_EXPR_P (var) = 1; DECL_ARTIFICIAL (var) = 1; diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template3.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template3.C new file mode 100644 index 0000000..fd6f1d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template3.C @@ -0,0 +1,33 @@ +// PR c++/49554 +// { dg-options -std=c++0x } + +template + struct base + { + struct iterator { }; + + iterator begin(); + }; + +template +class flist : public base +{ + typedef base Base; + + typedef typename Base::iterator Base_iterator; +public: + + void + resize() + { + Base_iterator b = Base::begin(); + + [b](int i) { return i; }; + } +}; + +void test01() +{ + flist fl; + fl.resize(); +}