From patchwork Thu Jan 30 21:00:25 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 315460 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 1075B2C009E for ; Fri, 31 Jan 2014 08:00:46 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=viIlHKnRYxj74k6DwJR4D/apZ2PFxN+G7syXa+dVtRvo0D ywGqERq3YlKp2iS3TKGIjJF7dCdJffRLPs6wvN9C98ER8p4Zqr3Zm557/bBNFodE CMA3PS3TLdOhglNM+LJtCG/p1Yic/6aSJC1PQQ2zROY1HpEAIUhohLwt1B18o= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=5wsrtOg9lQKtkDzgz6DLrYgCfL0=; b=GRcsU8YN0UtnTZvz2Le4 kqrEsVfU/9k6UpNF2qySymhuxsJMj4NlH8BLSy7IFEgy4yc6rljqLp7CKUZEXIM+ 9q3JjcRRaAEKEV1ToyQO8F5PnwOqeJxrMRdWh6JB9emqJW87w5IfazvjrURFj26W am5G0KsPxNew6s/U3e2Y6pE= Received: (qmail 17808 invoked by alias); 30 Jan 2014 21:00:40 -0000 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 Received: (qmail 17795 invoked by uid 89); 30 Jan 2014 21:00:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.2 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 30 Jan 2014 21:00:38 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s0UL0QlS012881 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 30 Jan 2014 16:00:31 -0500 Received: from [10.10.116.19] ([10.10.116.19]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id s0UL0P9G020811; Thu, 30 Jan 2014 16:00:25 -0500 Message-ID: <52EABD69.1020705@redhat.com> Date: Thu, 30 Jan 2014 16:00:25 -0500 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.2.0 MIME-Version: 1.0 To: gcc-patches List , Richard Biener Subject: RFA (pointer-set): PATCH for c++/57899 (infinite recursion with std::bind) In this testcase, the problem was that one instantiation of _Mu::operator() recursively calls another one, and we were finding a specialization of the arg parameter in local_specializations from the first instantiation, leading to a wrong result and infinite recursion. This patch fixes the problem by properly clearing local_specializations when we push_to_top_level so that the second instantiation won't find the specialization from the first one. Also, in the past we've had issues with nested functions in templates being able to refer to static/const variables from the enclosing context; we've dealt with that by forcing repeated lookup, but it would be better to keep the local_specializations from the enclosing function around so we can find them the usual way. To that end, I've added a pointer_map_copy. Tested x86_64-pc-linux-gnu. Is the pointer_map_copy change OK for trunk? 2014-01-30 Jason Merrill PR c++/57899 gcc/ * pointer-set.c (pointer_map_copy): New. * pointer-set.h: Declare it. gcc/cp/ * cp-tree.h (struct saved_scope): Add x_local_specializations. (local_specializations): New macro. * pt.c (local_specializations): Remove variable. (instantiate_decl): Only create new local_specializations if we did push_to_top_level. diff --git a/gcc/pointer-set.c b/gcc/pointer-set.c index 8b6a732..fdd9275 100644 --- a/gcc/pointer-set.c +++ b/gcc/pointer-set.c @@ -192,6 +192,19 @@ pointer_map_create (void) return result; } +/* Duplicate an existing pointer map. */ +struct pointer_map_t * +pointer_map_copy (pointer_map_t *p) +{ + struct pointer_map_t *result = XNEW (struct pointer_map_t); + result->pset.n_elements = p->pset.n_elements; + result->pset.log_slots = p->pset.log_slots; + result->pset.n_slots = p->pset.n_slots; + result->pset.slots = XDUPVEC (const void *, p->pset.slots, p->pset.n_slots); + result->values = XDUPVEC (void *, p->values, p->pset.n_slots); + return result; +} + /* Reclaims all memory associated with PMAP. */ void pointer_map_destroy (struct pointer_map_t *pmap) { diff --git a/gcc/pointer-set.h b/gcc/pointer-set.h index a426534..67f6527 100644 --- a/gcc/pointer-set.h +++ b/gcc/pointer-set.h @@ -159,6 +159,7 @@ pointer_map::traverse (bool (*fn) (const void *, T *, void *), void *data) struct pointer_map_t; pointer_map_t *pointer_map_create (void); +pointer_map_t *pointer_map_copy (pointer_map_t *); void pointer_map_destroy (pointer_map_t *pmap); void **pointer_map_contains (const pointer_map_t *pmap, const void *p); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7f46499..7681b27 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1049,6 +1049,8 @@ struct GTY(()) saved_scope { cp_binding_level *class_bindings; cp_binding_level *bindings; + struct pointer_map_t *x_local_specializations; + struct saved_scope *prev; }; @@ -1098,6 +1100,12 @@ struct GTY(()) saved_scope { #define previous_class_level scope_chain->x_previous_class_level +/* A map from local variable declarations in the body of the template + presently being instantiated to the corresponding instantiated + local variables. */ + +#define local_specializations scope_chain->x_local_specializations + /* A list of private types mentioned, for deferred access checking. */ extern GTY(()) struct saved_scope *scope_chain; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4a5b6cc..43aeaa0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -78,11 +78,6 @@ static GTY(()) tree saved_access_scope; to the EXPR_STMT that is its result. */ static tree cur_stmt_expr; -/* A map from local variable declarations in the body of the template - presently being instantiated to the corresponding instantiated - local variables. */ -static struct pointer_map_t *local_specializations; - /* True if we've recursed into fn_type_unification too many times. */ static bool excessive_deduction_depth; @@ -19637,7 +19632,15 @@ instantiate_decl (tree d, int defer_ok, saved_local_specializations = local_specializations; /* Set up the list of local specializations. */ - local_specializations = pointer_map_create (); + if (fn_context + && !(DECL_CLASS_SCOPE_P (d) && LAMBDA_TYPE_P (DECL_CONTEXT (d)))) + /* Normally in a nested function we want to be able to look up + variables from the enclosing function. But in a lambda we've + already remapped everything to refer to the closure, and we + might be instantiating from outside the enclosing function. */ + local_specializations = pointer_map_copy (local_specializations); + else + local_specializations = pointer_map_create (); /* Set up context. */ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern) diff --git a/libstdc++-v3/testsuite/20_util/bind/57899.cc b/libstdc++-v3/testsuite/20_util/bind/57899.cc new file mode 100644 index 0000000..d46d53e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bind/57899.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2010-2014 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 20.7.11 Function template bind + +// PR c++/57899 +// { dg-do compile } +// { dg-options -std=c++11 } + +#include +using std::bind; +using std::placeholders::_1; + +struct S { int i; }; + +struct P { S s; }; + +struct get_s +{ + const S& operator()(const P& p) const { return p.s; } +} gs; + +int gi(const S& s) { return s.i; } + +bool cmp(int, int) { return true; } + +int main() +{ + P p{}; + auto f1 = bind(gs, _1); + auto f2 = bind(gi, f1); + auto f3 = bind(cmp, f2, 5); + f3(p); +}