/*conversion_path=*/NULL_TREE,
/*access_path=*/NULL_TREE,
LOOKUP_NORMAL,
- candidates, complain);
+ candidates, complain & ~tf_any_viable);
*candidates = splice_viable (*candidates, false, any_viable_p);
if (*any_viable_p)
- cand = tourney (*candidates, complain);
+ {
+ if (complain & tf_any_viable)
+ cand = *candidates;
+ else
+ cand = tourney (*candidates, complain);
+ }
else
cand = NULL;
if (args != NULL && *args != NULL)
{
- *args = resolve_args (*args, complain);
+ *args = resolve_args (*args, complain & ~tf_any_viable);
if (*args == NULL)
return error_mark_node;
}
}
result = error_mark_node;
}
+ else if (complain & tf_any_viable)
+ return void_node;
else
- {
- result = build_over_call (cand, LOOKUP_NORMAL, complain);
- }
+ result = build_over_call (cand, LOOKUP_NORMAL, complain);
if (flag_coroutines
&& result
for calls in decltype (5.2.2/11). */
tf_partial = 1 << 8, /* Doing initial explicit argument
substitution in fn_type_unification. */
- tf_fndecl_type = 1 << 9, /* Substituting the type of a function
- declaration. */
- tf_no_cleanup = 1 << 10, /* Do not build a cleanup
- (build_target_expr and friends) */
- /* 1 << 11 is available. */
+ tf_fndecl_type = 1 << 9, /* Substituting the type of a function
+ declaration. */
+ tf_no_cleanup = 1 << 10, /* Do not build a cleanup
+ (build_target_expr and friends) */
+ tf_any_viable = 1 << 11, /* Return void_node if there are any viable
+ candidates. Currently only supported on
+ finish_call_expr on perform_koenig_lookup
+ result. */
tf_tst_ok = 1 << 12, /* Allow a typename-specifier to name
a template (C++17 or later). */
- tf_dguide = 1 << 13, /* Building a deduction guide from a ctor. */
+ tf_dguide = 1 << 13, /* Building a deduction guide from a ctor. */
tf_qualifying_scope = 1 << 14, /* Substituting the LHS of the :: operator.
Affects TYPENAME_TYPE resolution from
make_typename_type. */
- tf_no_name_lookup = 1 << 15, /* Don't look up the terminal name of an
- outermost id-expression, or resolve its
- constituent template-ids or qualified-ids. */
+ tf_no_name_lookup = 1 << 15, /* Don't look up the terminal name of an
+ outermost id-expression, or resolve its
+ constituent template-ids or
+ qualified-ids. */
/* Convenient substitution flags combinations. */
tf_warning_or_error = tf_warning | tf_error
};
static void do_range_for_auto_deduction
(tree, tree, cp_decomp *, bool);
static tree cp_range_for_member_function
- (tree, tree);
+ (tree, tree, tsubst_flags_t);
static tree cp_parser_expansion_statement
(cp_parser *, bool *);
static tree cp_parser_jump_statement
if (member_begin != NULL_TREE && member_end != NULL_TREE)
{
/* Use the member functions. */
- *begin = cp_range_for_member_function (range, id_begin);
- *end = cp_range_for_member_function (range, id_end);
+ *begin = cp_range_for_member_function (range, id_begin, complain);
+ *end = cp_range_for_member_function (range, id_end, complain);
}
else
{
vec_safe_push (vec, range);
- member_begin = perform_koenig_lookup (id_begin, vec,
- complain);
+ member_begin = perform_koenig_lookup (id_begin, vec, complain);
if ((complain & tf_error) == 0 && member_begin == id_begin)
return error_mark_node;
*begin = finish_call_expr (member_begin, &vec, false, true,
complain);
- member_end = perform_koenig_lookup (id_end, vec,
- tf_warning_or_error);
+ member_end = perform_koenig_lookup (id_end, vec, complain);
if ((complain & tf_error) == 0 && member_end == id_end)
{
*begin = error_mark_node;
}
*end = finish_call_expr (member_end, &vec, false, true,
complain);
+ if ((complain & tf_error) == 0
+ && (*begin == error_mark_node || *end == error_mark_node))
+ {
+ /* Expansion stmt should be iterating if there are any
+ viable candidates for begin and end. If both finish_call_expr
+ with tf_none succeeded, there certainly are, if not,
+ retry with tf_any_viable to check if there were any viable
+ candidates. */
+ if (*begin == error_mark_node
+ && finish_call_expr (member_begin, &vec, false, true,
+ tf_any_viable) == error_mark_node)
+ {
+ *end = error_mark_node;
+ return error_mark_node;
+ }
+ if (*end == error_mark_node
+ && finish_call_expr (member_end, &vec, false, true,
+ tf_any_viable) == error_mark_node)
+ {
+ *begin = error_mark_node;
+ return error_mark_node;
+ }
+ }
}
/* Last common checks. */
{
/* If one of the expressions is an error do no more checks. */
*begin = *end = error_mark_node;
+ /* But signal to finish_expansion_stmt whether this is
+ destructuring (error_mark_node returned) or iterating
+ (something else returned). If we got here, range.begin and
+ range.end members were found or begin (range) and end (range)
+ found any viable candidates. */
+ if ((complain & tf_error) == 0)
+ return NULL_TREE;
return error_mark_node;
}
else if (type_dependent_expression_p (*begin)
Builds a tree for RANGE.IDENTIFIER(). */
static tree
-cp_range_for_member_function (tree range, tree identifier)
+cp_range_for_member_function (tree range, tree identifier,
+ tsubst_flags_t complain)
{
tree member, res;
member = finish_class_member_access_expr (range, identifier,
- false, tf_warning_or_error);
+ false, complain);
if (member == error_mark_node)
return error_mark_node;
releasing_vec vec;
res = finish_call_expr (member, &vec,
/*disallow_virtual=*/false,
- /*koenig_p=*/false,
- tf_warning_or_error);
+ /*koenig_p=*/false, complain);
return res;
}
range_temp = convert_from_reference (build_range_temp (expansion_init));
iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
&end_expr, tf_none);
- if (begin_expr != error_mark_node && end_expr != error_mark_node)
- {
- kind = esk_iterating;
- gcc_assert (iter_type);
- }
+ if (iter_type != error_mark_node
+ || (begin_expr != error_mark_node && (end_expr != error_mark_node)))
+ kind = esk_iterating;
}
if (kind == esk_iterating)
{
tree result;
tree orig_fn;
vec<tree, va_gc> *orig_args = *args;
+ tsubst_flags_t orig_complain = complain;
if (fn == error_mark_node)
return error_mark_node;
+ complain &= ~tf_any_viable;
gcc_assert (!TYPE_P (fn));
/* If FN may be a FUNCTION_DECL obfuscated by force_paren_expr, undo
}
/* A call to a namespace-scope function. */
- result = build_new_function_call (fn, args, complain);
+ result = build_new_function_call (fn, args, orig_complain);
}
}
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
--- /dev/null
+// CWG 3123
+// { dg-do run { target c++26 } }
+
+#include <tuple>
+
+int
+main ()
+{
+ long l = 0;
+ std::tuple <int, long, unsigned> t = { 1, 2L, 3U };
+ template for (auto &&x : t)
+ l += x;
+ if (l != 6L)
+ __builtin_abort ();
+}
--- /dev/null
+// CWG 3123
+// { dg-do compile { target c++26 } }
+
+namespace M {
+ struct B {};
+
+ template <typename T>
+ auto *begin (T &t) { return &t.array[0]; }
+}
+
+namespace N {
+ struct S : M::B { int array[8]; };
+
+ template <typename T>
+ auto *begin (T &s) { return &s.array[0]; }
+
+ auto *end (const S &s) { return &s.array[8]; }
+}
+
+struct V { int begin, end; };
+
+namespace O {
+ struct B { int b; };
+ struct C { int operator () (int) { return 42; } } begin, end;
+}
+
+void
+foo ()
+{
+ for (auto i : N::S {}) // { dg-error "call of overloaded 'begin\\\(N::S\\\&\\\)' is ambiguous" }
+ ;
+ template for (auto i : N::S {})
+ ; // { dg-error "call of overloaded 'begin\\\(const N::S\\\&\\\)' is ambiguous" }
+ template for (auto i : V {})
+ ; // { dg-error "cannot be used as a function" }
+ template for (auto i : O::B {})
+ ;
+}