From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id D89BB384B835; Thu, 21 Jul 2022 16:48:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D89BB384B835 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-8605] c++: dependence of constrained memfn from current inst [PR105842] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/releases/gcc-12 X-Git-Oldrev: 670ef5b108d0acfbde96f44b064079f2fa0c92d4 X-Git-Newrev: 5d6286903f325a7a85e5ab1d04ba942d33d755bc Message-Id: <20220721164817.D89BB384B835@sourceware.org> Date: Thu, 21 Jul 2022 16:48:17 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Jul 2022 16:48:18 -0000 https://gcc.gnu.org/g:5d6286903f325a7a85e5ab1d04ba942d33d755bc commit r12-8605-g5d6286903f325a7a85e5ab1d04ba942d33d755bc Author: Patrick Palka Date: Wed Jul 13 14:01:28 2022 -0400 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 f07778f6f92111aa0abfd0f669b148a0bda537a9) Diff: --- gcc/cp/constraint.cc | 22 +++++++++++---- gcc/cp/cp-tree.h | 1 + gcc/cp/pt.cc | 39 ++++++++++++++++++++++---- gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C | 34 ++++++++++++++++++++++ 4 files changed, 84 insertions(+), 12 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 94f6222b436..ab238dbb4cb 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -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; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2db847868b6..72f4398a8f9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 38c138bd835..cf4ae7775da 100644 --- a/gcc/cp/pt.cc +++ b/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; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C new file mode 100644 index 00000000000..0e09ae6ed4c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl6.C @@ -0,0 +1,34 @@ +// PR c++/105842 +// { dg-do compile { target c++20 } } + +template +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 static void tmpl1() requires __is_same(T, int); + template static void tmpl1() requires (!__is_same(T, int)); + + template static void tmpl2() requires (sizeof...(Us) == 1); + template 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::foo(); +}