c++: dependence of constrained memfn from current inst [PR105842]
Here we incorrectly deem the calls to func1, func2 and tmpl2 as
ambiguous ahead of time ultimately because we mishandle dependence
of a constrained member function from the current instantiation.
In type_dependent_expression_p, we already consider dependence of a
TEMPLATE_DECL's constraints (via uses_outer_template_parms), but
neglect to do the same for a FUNCTION_DECL (such as that for func1).
And in satisfy_declaration_constraints, we give up if _any_ template
argument is dependent, but for non-dependent member functions from
the current instantiation (such as func2 and tmpl2), we can and must
check constraints as long as the innermost arguments aren't dependent.
PR c++/105842
gcc/cp/ChangeLog:
* constraint.cc (satisfy_declaration_constraints): Refine early
exit test for argument dependence.
* cp-tree.h (uses_outer_template_parms_in_constraints): Declare.
* pt.cc (template_class_depth): Handle TI_TEMPLATE being a
FIELD_DECL.
(usse_outer_template_parms): Factor out constraint dependence
test into ...
(uses_outer_template_parms_in_constraints): ... here.
(type_dependent_expression_p): Use it for FUNCTION_DECL.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-memtmpl6.C: New test.
(cherry picked from commit f07778f6f9
)
This commit is contained in:
parent
670ef5b108
commit
5d6286903f
|
@ -3179,9 +3179,15 @@ satisfy_declaration_constraints (tree t, sat_info info)
|
|||
args = regen_args;
|
||||
}
|
||||
|
||||
/* If any arguments depend on template parameters, we can't
|
||||
check constraints. Pretend they're satisfied for now. */
|
||||
if (uses_template_parms (args))
|
||||
/* If the innermost arguments are dependent, or if the outer arguments
|
||||
are dependent and are needed by the constraints, we can't check
|
||||
satisfaction yet so pretend they're satisfied for now. */
|
||||
if (uses_template_parms (args)
|
||||
&& ((DECL_TEMPLATE_INFO (t)
|
||||
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t))
|
||||
&& (TMPL_ARGS_DEPTH (args) == 1
|
||||
|| uses_template_parms (INNERMOST_TEMPLATE_ARGS (args))))
|
||||
|| uses_outer_template_parms_in_constraints (t)))
|
||||
return boolean_true_node;
|
||||
|
||||
/* Get the normalized constraints. */
|
||||
|
@ -3243,9 +3249,13 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)
|
|||
else
|
||||
args = add_outermost_template_args (t, args);
|
||||
|
||||
/* If any arguments depend on template parameters, we can't
|
||||
check constraints. Pretend they're satisfied for now. */
|
||||
if (uses_template_parms (args))
|
||||
/* If the innermost arguments are dependent, or if the outer arguments
|
||||
are dependent and are needed by the constraints, we can't check
|
||||
satisfaction yet so pretend they're satisfied for now. */
|
||||
if (uses_template_parms (args)
|
||||
&& (TMPL_ARGS_DEPTH (args) == 1
|
||||
|| uses_template_parms (INNERMOST_TEMPLATE_ARGS (args))
|
||||
|| uses_outer_template_parms_in_constraints (t)))
|
||||
return boolean_true_node;
|
||||
|
||||
tree result = boolean_true_node;
|
||||
|
|
|
@ -7317,6 +7317,7 @@ extern tree lookup_template_function (tree, tree);
|
|||
extern tree lookup_template_variable (tree, tree);
|
||||
extern int uses_template_parms (tree);
|
||||
extern bool uses_template_parms_level (tree, int);
|
||||
extern bool uses_outer_template_parms_in_constraints (tree);
|
||||
extern bool in_template_function (void);
|
||||
extern bool need_generic_capture (void);
|
||||
extern tree instantiate_class_template (tree);
|
||||
|
|
39
gcc/cp/pt.cc
39
gcc/cp/pt.cc
|
@ -389,7 +389,9 @@ template_class_depth (tree type)
|
|||
{
|
||||
tree tinfo = get_template_info (type);
|
||||
|
||||
if (tinfo && PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))
|
||||
if (tinfo
|
||||
&& TREE_CODE (TI_TEMPLATE (tinfo)) == TEMPLATE_DECL
|
||||
&& PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo))
|
||||
&& uses_template_parms (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo))))
|
||||
++depth;
|
||||
|
||||
|
@ -10953,7 +10955,7 @@ uses_template_parms_level (tree t, int level)
|
|||
/* Returns true if the signature of DECL depends on any template parameter from
|
||||
its enclosing class. */
|
||||
|
||||
bool
|
||||
static bool
|
||||
uses_outer_template_parms (tree decl)
|
||||
{
|
||||
int depth = template_class_depth (CP_DECL_CONTEXT (decl));
|
||||
|
@ -10984,13 +10986,27 @@ uses_outer_template_parms (tree decl)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if (uses_outer_template_parms_in_constraints (decl))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns true if the constraints of DECL depend on any template parameters
|
||||
from its enclosing scope. */
|
||||
|
||||
bool
|
||||
uses_outer_template_parms_in_constraints (tree decl)
|
||||
{
|
||||
tree ci = get_constraints (decl);
|
||||
if (ci)
|
||||
ci = CI_ASSOCIATED_CONSTRAINTS (ci);
|
||||
if (ci && for_each_template_parm (ci, template_parm_outer_level,
|
||||
&depth, NULL, /*nondeduced*/true))
|
||||
return true;
|
||||
return false;
|
||||
if (!ci)
|
||||
return false;
|
||||
int depth = template_class_depth (CP_DECL_CONTEXT (decl));
|
||||
if (depth == 0)
|
||||
return false;
|
||||
return for_each_template_parm (ci, template_parm_outer_level,
|
||||
&depth, NULL, /*nondeduced*/true);
|
||||
}
|
||||
|
||||
/* Returns TRUE iff INST is an instantiation we don't need to do in an
|
||||
|
@ -27982,6 +27998,17 @@ type_dependent_expression_p (tree expression)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Otherwise, its constraints could still depend on outer template parameters
|
||||
from its (dependent) scope. */
|
||||
if (TREE_CODE (expression) == FUNCTION_DECL
|
||||
/* As an optimization, check this cheaper sufficient condition first.
|
||||
(At this point we've established that we're looking at a member of
|
||||
a dependent class, so it makes sense to start treating say undeduced
|
||||
auto as dependent.) */
|
||||
&& !dependent_type_p (TREE_TYPE (expression))
|
||||
&& uses_outer_template_parms_in_constraints (expression))
|
||||
return true;
|
||||
|
||||
/* Always dependent, on the number of arguments if nothing else. */
|
||||
if (TREE_CODE (expression) == EXPR_PACK_EXPANSION)
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// PR c++/105842
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
template<class T>
|
||||
struct S {
|
||||
static void func1() requires __is_same(T, int);
|
||||
static void func1() requires (!__is_same(T, int));
|
||||
|
||||
static void func2() requires false && false;
|
||||
static void func2() requires false;
|
||||
|
||||
template<class...> static void tmpl1() requires __is_same(T, int);
|
||||
template<class...> static void tmpl1() requires (!__is_same(T, int));
|
||||
|
||||
template<class... Us> static void tmpl2() requires (sizeof...(Us) == 1);
|
||||
template<class... Us> static void tmpl2() requires (sizeof...(Us) == 2);
|
||||
|
||||
static void foo() {
|
||||
// Both calls resolve to the first overload at instantiation time.
|
||||
func1();
|
||||
tmpl1();
|
||||
}
|
||||
|
||||
static void bar() {
|
||||
// We can check and reject both calls ahead of time since the functions'
|
||||
// constraints don't depend on outer template parameters.
|
||||
func2(); // { dg-error "no match" }
|
||||
tmpl2(); // { dg-error "no match" }
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
S<int>::foo();
|
||||
}
|
Loading…
Reference in New Issue