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.
This commit is contained in:
parent
f35d65517a
commit
f07778f6f9
4 changed files with 84 additions and 12 deletions
|
@ -3176,9 +3176,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. */
|
||||
|
@ -3240,9 +3246,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;
|
||||
|
|
|
@ -7297,6 +7297,7 @@ extern tree lookup_template_function (tree, tree);
|
|||
extern tree lookup_template_variable (tree, tree);
|
||||
extern bool 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
|
@ -391,7 +391,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;
|
||||
|
||||
|
@ -11011,7 +11013,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));
|
||||
|
@ -11042,13 +11044,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
|
||||
|
@ -28103,6 +28119,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;
|
||||
|
|
34
gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C
Normal file
34
gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C
Normal file
|
@ -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…
Add table
Reference in a new issue