On Wed, Mar 20, 2019 at 10:34:51AM -0400, Nathan Sidwell wrote:
> On 3/19/19 2:14 PM, Jakub Jelinek wrote:
> > add_capture when parsing a lambda introducer uses the IDENTIFIER_MARKED
> > bit to detect duplicate captures.
> > I guess in strict C++11 that could have worked, if the introducer could
> > contain just identifiers, but in C++14 it has 2 problems:
>
> > The following patch stops using IDENTIFIER_MARKED for this and uses a
> > hash_set instead. But, as I believe lambdas with 0 (or very few) explicit
> > captures are extremely common, I've tried not to slow down those with
> > allocation of a hash_set and deallocating it again, so it uses
> > a linear search if there are up to 8 captures and starts using a hash_set
> > only when getting above that count.
> >
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> >
> > Or do you think allocation of an hash_set and deallocation would be in a
> > noise?
>
> I think it'd be in the noise. The high bit is between zero and more than
> zero captures. The next most common after zero would be 1. Besides,
> identifiers are trivial to hash.
What I meant is that even just hash_set var; implies a xcalloc (13,
sizeof (void*)) or so and destroying it a free of that.
So, if 90% of all lambdas in the headers have zero captures and 5% have 1,
then simplifying the patch by adding that hash_set var; into the
lambda introducer parsing routine and just always using the hash set would
add those to the parsing of all those 95%+ lambda parsings that don't really
need that.
Here is attached completely untested variant that does that unconditional
xcalloc/free for every lambda introducer parsing.
The previously posted patch was:
cp/cp-tree.h |3 +
cp/lambda.c| 54 -
cp/parser.c| 10 --
this variant is:
cp/cp-tree.h |3 ++-
cp/lambda.c| 14 +++---
cp/parser.c|7 ---
2019-03-20 Jakub Jelinek
PR c++/89767
* cp-tree.h (add_capture): Add ids argument.
* parser.c (cp_parser_lambda_introducer): Add ids variable and pass
its address to add_capture calls.
* lambda.c (add_capture): Add ids argument, don't use
IDENTIFIER_MARKED, instead use ids hash_set for that.
(register_capture_members): Don't clear IDENTIFIER_MARKED here.
(add_default_capture): Adjust add_capture caller.
* g++.dg/cpp1y/lambda-init18.C: New test.
* g++.dg/cpp1y/lambda-init19.C: New test.
* g++.dg/cpp1y/pr89767.C: New test.
--- gcc/cp/cp-tree.h.jj 2019-03-19 17:10:03.135143659 +0100
+++ gcc/cp/cp-tree.h2019-03-20 15:41:53.561214488 +0100
@@ -7150,7 +7150,8 @@ extern tree lambda_return_type(tree);
extern tree lambda_proxy_type (tree);
extern tree lambda_function(tree);
extern void apply_deduced_return_type (tree, tree);
-extern tree add_capture (tree, tree, tree, bool, bool);
+extern tree add_capture (tree, tree, tree, bool, bool,
+hash_set *);
extern tree add_default_capture (tree, tree, tree);
extern void insert_capture_proxy (tree);
extern void insert_pending_capture_proxies (void);
--- gcc/cp/parser.c.jj 2019-03-19 17:10:03.074144632 +0100
+++ gcc/cp/parser.c 2019-03-20 15:42:44.165434239 +0100
@@ -10547,6 +10547,7 @@ cp_parser_lambda_introducer (cp_parser*
error ("non-local lambda expression cannot have a capture-default");
}
+ hash_set ids;
while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
{
cp_token* capture_token;
@@ -10586,7 +10587,7 @@ cp_parser_lambda_introducer (cp_parser*
/*id=*/this_identifier,
/*initializer=*/finish_this_expr (),
/*by_reference_p=*/true,
- explicit_init_p);
+ explicit_init_p, );
continue;
}
@@ -10604,7 +10605,7 @@ cp_parser_lambda_introducer (cp_parser*
/*id=*/this_identifier,
/*initializer=*/finish_this_expr (),
/*by_reference_p=*/false,
- explicit_init_p);
+ explicit_init_p, );
continue;
}
@@ -10757,7 +10758,7 @@ cp_parser_lambda_introducer (cp_parser*
capture_id,
capture_init_expr,
/*by_reference_p=*/capture_kind == BY_REFERENCE,
- explicit_init_p);
+ explicit_init_p, );
/* If there is any qualification still in effect, clear it
now; we will be starting fresh with the next capture. */
--- gcc/cp/lambda.c.jj