On Tue, Jun 9, 2020 at 5:04 AM Iain Sandoe <i...@sandoe.co.uk> wrote:
> Hi C++ folks, > > There are a number of places in the coroutine codegen where we need to > build calls to promise methods. > > Such methods can, in several cases, also be constexpr or static (or both) > which leads to the PR, > > Now the mechanism I use is this; > > 1/ lookup the method in the relevant scope > > tree method > = lookup_member (promise, member_id, /*protect=*/1, /*want_type=*/0, > tf_warning_or_error); > > - this returns a BASELINK tree.. > > 2/ In many cases, the calls are to methods with no parms. > > so, with a dummy object, I do: > > tree call > = build_new_method_call (dummy, method, NULL, NULL_TREE, LOOKUP_NORMAL, > NULL, flags); > > ‘args’ is the 3rd parm. > > 3/ The header comment on build_new_method_call says: > > /* Build a call to "INSTANCE.FN (ARGS)". If FN_P is non-NULL, it will > be set, upon return, to the function called. ARGS may be NULL. > This may change ARGS. */ > > Which says that the 3rd arg can validly be NULL (as per my example). > > 4/ however, inside build_new_method_call ‘args' gets assigned to > ‘user_args’ which is used in a lot of places without any guard to see if > it’s non-null. One of those places is passing it to add_candidates (), > which eventually in the case of a static method uses the pointer and ICEs. > > ===== > > So… > > A/ I’m doing something wrong, and my use of APIs is violating an > expectation (in which case what’s the right API usage?) > > B/ It happens to be other callers to build_new_method_call() have either > had dummy args or not produced the same set of conditions > It does seem that most callers use dummy args, but the function isn't documented that way, and it seems preferable to allow null args. (for my case of static promise methods) > > * if I provide an empty dummy ‘args' to the build_new_method_call it > works > * if I fix the unguarded use of ‘args' in add_candidates (as below) it > works, > > AFAICT, the intent is to avoid every caller for build_new_method_call() > having to build a dummy argument list when that list is empty - it would > seem irritating to have to add one for every use in coros - but I can. > > WDYT? > thanks > Iain > > -------- > > the fix for call.c: > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c > index 3c97b9846e2..dccc1bf596f 100644 > --- a/gcc/cp/call.c > +++ b/gcc/cp/call.c > @@ -5862,7 +5862,7 @@ add_candidates (tree fns, tree first_arg, const > vec<tree, va_gc> *args, > } > > /* Don't bother reversing an operator with two identical > parameters. */ > - else if (args->length () == 2 && (flags & LOOKUP_REVERSED)) > + else if (args && args->length () == 2 && (flags & LOOKUP_REVERSED)) > The usual pattern is to use vec_safe_length here. Similarly, in build_new_method_call_1 I think !user_args->is_empty() should be vec_safe_is_empty (user_args) Those changes are OK. Jason