* [PATCH] Fix auto deduction for template specialization scopes [114915].
@ 2024-05-01 22:52 Seyed Sajad Kahani
2024-05-03 16:24 ` Patrick Palka
2024-05-22 15:41 ` [PATCH] Fix auto deduction for template specialization scopes [114915] Jason Merrill
0 siblings, 2 replies; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-05-01 22:52 UTC (permalink / raw)
To: gcc-patches; +Cc: Seyed Sajad Kahani
When deducing auto for `adc_return_type`, `adc_variable_type`, and `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost template arguments to be used for satisfaction. This is done by one of the following, depending on the scope:
1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other conditions) for non-function scope variable declaration deductions (decl.cc:8527).
Then, we do not retrieve the deeper layers of the template arguments; instead, we fill the missing levels with dummy levels (pt.cc:31260).
The problem (that is shown in PR114915) is that we do not consider the case where the deduction happens in a template specialization scope. In this case, the type is not dependent on the outermost template arguments (which are the specialization arguments). Yet, we still resolve the outermost template arguments, and then the number of layers in the template arguments exceeds the number of levels in the type. This causes the missing levels to be negative. This leads to the rejection of valid code and ICEs (like segfault) in the release mode. In the debug mode, it is possible to show as an assertion failure (when creating a tree_vec with a negative size).
The code that generates the issue is added to the test suite as `g++.dg/cpp2a/concepts-placeholder14.C`.
This patch fixes the issue by checking that the template usage, whose arguments are going to be used for satisfaction, is not a partial or explicit specialization (and therefore it is an implicit or explicit instantiation). This check is done in the two only places that affect the `outer_targs` for the mentioned contexts.
One might ask why this is not implemented as a simple `missing_level > 0` check. The reason is that the recovery from the negative `missing_levels` will not be easy, and it is not clear how to recover from it. Therefore, it is better to prevent it from happening.
---
gcc/cp/decl.cc | 1 +
gcc/cp/pt.cc | 16 ++++++++++-----
.../g++.dg/cpp2a/concepts-placeholder14.C | 20 +++++++++++++++++++
3 files changed, 32 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 65ab64885..7e51f926e 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8527,6 +8527,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (PLACEHOLDER_TYPE_CONSTRAINTS_INFO (auto_node)
&& DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_INFO (decl)
+ && DECL_USE_TEMPLATE (decl) != 2
&& !DECL_FUNCTION_SCOPE_P (decl))
/* The outer template arguments might be needed for satisfaction.
(For function scope variables, do_auto_deduction will obtain the
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3b2106dd3..fd646d873 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree init)
OUTER_TARGS is used during template argument deduction (context == adc_unify)
to properly substitute the result. It's also used in the adc_unify and
adc_requirement contexts to communicate the necessary template arguments
- to satisfaction. OUTER_TARGS is ignored in other contexts.
+ to satisfaction. OUTER_TARGS will be used for other contexts if it is a
+ function scope deduction. Otherwise it is ignored.
Additionally for adc_unify contexts TMPL is the template for which TYPE
is a template parameter type.
@@ -31235,8 +31236,11 @@ do_auto_deduction (tree type, tree init, tree auto_node,
if (tree fn = current_function_decl)
if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
{
- outer_targs = DECL_TEMPLATE_INFO (fn)
- ? DECL_TI_ARGS (fn) : NULL_TREE;
+ outer_targs = NULL_TREE;
+ if (DECL_TEMPLATE_INFO (fn) && DECL_USE_TEMPLATE (fn) != 2)
+ {
+ outer_targs = DECL_TI_ARGS (fn);
+ }
if (LAMBDA_FUNCTION_P (fn))
{
/* As in satisfy_declaration_constraints. */
@@ -31260,8 +31264,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- - TMPL_ARGS_DEPTH (full_targs)))
+ int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
+ - TMPL_ARGS_DEPTH (full_targs));
+
+ if (missing_levels > 0)
{
tree dummy_levels = make_tree_vec (missing_levels);
for (int i = 0; i < missing_levels; ++i)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..4a98ec7b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,20 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept TheConcept = __is_same(T, int);
+
+template<typename T>
+void f() {
+ TheConcept auto x = 1;
+}
+
+template<>
+void f<int>() {
+ TheConcept auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
--
2.44.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Fix auto deduction for template specialization scopes [114915].
2024-05-01 22:52 [PATCH] Fix auto deduction for template specialization scopes [114915] Seyed Sajad Kahani
@ 2024-05-03 16:24 ` Patrick Palka
2024-05-04 14:11 ` Seyed Sajad Kahani
2024-05-22 15:41 ` [PATCH] Fix auto deduction for template specialization scopes [114915] Jason Merrill
1 sibling, 1 reply; 25+ messages in thread
From: Patrick Palka @ 2024-05-03 16:24 UTC (permalink / raw)
To: Seyed Sajad Kahani; +Cc: gcc-patches, jason
Thanks for the patch!
On Wed, 1 May 2024, Seyed Sajad Kahani wrote:
> When deducing auto for `adc_return_type`, `adc_variable_type`, and `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost template arguments to be used for satisfaction. This is done by one of the following, depending on the scope:
>
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other conditions) for non-function scope variable declaration deductions (decl.cc:8527).
>
> Then, we do not retrieve the deeper layers of the template arguments; instead, we fill the missing levels with dummy levels (pt.cc:31260).
>
> The problem (that is shown in PR114915) is that we do not consider the case where the deduction happens in a template specialization scope. In this case, the type is not dependent on the outermost template arguments (which are the specialization arguments). Yet, we still resolve the outermost template arguments, and then the number of layers in the template arguments exceeds the number of levels in the type. This causes the missing levels to be negative. This leads to the rejection of valid code and ICEs (like segfault) in the release mode. In the debug mode, it is possible to show as an assertion failure (when creating a tree_vec with a negative size).
> The code that generates the issue is added to the test suite as `g++.dg/cpp2a/concepts-placeholder14.C`.
>
> This patch fixes the issue by checking that the template usage, whose arguments are going to be used for satisfaction, is not a partial or explicit specialization (and therefore it is an implicit or explicit instantiation). This check is done in the two only places that affect the `outer_targs` for the mentioned contexts.
>
> One might ask why this is not implemented as a simple `missing_level > 0` check. The reason is that the recovery from the negative `missing_levels` will not be easy, and it is not clear how to recover from it. Therefore, it is better to prevent it from happening.
> ---
> gcc/cp/decl.cc | 1 +
> gcc/cp/pt.cc | 16 ++++++++++-----
> .../g++.dg/cpp2a/concepts-placeholder14.C | 20 +++++++++++++++++++
> 3 files changed, 32 insertions(+), 5 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 65ab64885..7e51f926e 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -8527,6 +8527,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
> if (PLACEHOLDER_TYPE_CONSTRAINTS_INFO (auto_node)
> && DECL_LANG_SPECIFIC (decl)
> && DECL_TEMPLATE_INFO (decl)
> + && DECL_USE_TEMPLATE (decl) != 2
We should check !DECL_TEMPLATE_SPECIALIZATION instead of checking
DECL_USE_TEMPLATE directly.
And since DECL_TEMPLATE_SPECIALIZATION is true for both partial and
explicit specializations, I think we should check !in_template_context
as well in order to single out explicit specializations?
> && !DECL_FUNCTION_SCOPE_P (decl))
> /* The outer template arguments might be needed for satisfaction.
> (For function scope variables, do_auto_deduction will obtain the
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..fd646d873 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree init)
> OUTER_TARGS is used during template argument deduction (context == adc_unify)
> to properly substitute the result. It's also used in the adc_unify and
> adc_requirement contexts to communicate the necessary template arguments
> - to satisfaction. OUTER_TARGS is ignored in other contexts.
> + to satisfaction. OUTER_TARGS will be used for other contexts if it is a
> + function scope deduction. Otherwise it is ignored.
>
> Additionally for adc_unify contexts TMPL is the template for which TYPE
> is a template parameter type.
> @@ -31235,8 +31236,11 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> if (tree fn = current_function_decl)
> if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
> {
> - outer_targs = DECL_TEMPLATE_INFO (fn)
> - ? DECL_TI_ARGS (fn) : NULL_TREE;
> + outer_targs = NULL_TREE;
> + if (DECL_TEMPLATE_INFO (fn) && DECL_USE_TEMPLATE (fn) != 2)
> + {
> + outer_targs = DECL_TI_ARGS (fn);
> + }
Same here.
> if (LAMBDA_FUNCTION_P (fn))
> {
> /* As in satisfy_declaration_constraints. */
> @@ -31260,8 +31264,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> these missing levels, but this hack otherwise allows us to handle a
> large subset of possible constraints (including all non-dependent
> constraints). */
> - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> + int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> + - TMPL_ARGS_DEPTH (full_targs));
> +
> + if (missing_levels > 0)
IIUC this change is not necessary with the above changes, right? Maybe
we could assert than missing_levels is nonnegative.
Another more context-unaware approach to fix this might be to only
use the innermost level from 'full_targs' for satisfaction if
TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
appeared in a context that doesn't have template parameters such as an
explicit specialization or ordinary non-template function, and so
only the level corresponding to the deduced type is needed for
satisfaction.)
Generalizing on that, another approach might be to handle missing_levels < 0
by removing -missing_levels from full_targs via get_innermost_template_args.
But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
case specifically.
I wonder what Jason thinks?
> {
> tree dummy_levels = make_tree_vec (missing_levels);
> for (int i = 0; i < missing_levels; ++i)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 000000000..4a98ec7b3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,20 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T>
> +concept TheConcept = __is_same(T, int);
> +
> +template<typename T>
> +void f() {
> + TheConcept auto x = 1;
> +}
> +
> +template<>
> +void f<int>() {
> + TheConcept auto x = 1;
> +}
> +
> +int main() {
> + f<int>();
> + return 0;
> +}
It would be good to also test an explicit variable tmpl spec and
an explicit spec of a member template of a class template.
> --
> 2.44.0
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Fix auto deduction for template specialization scopes [114915].
2024-05-03 16:24 ` Patrick Palka
@ 2024-05-04 14:11 ` Seyed Sajad Kahani
2024-05-04 15:15 ` [PATCH v2] Fix auto deduction for template specialization scopes [PR114915] Seyed Sajad Kahani
0 siblings, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-05-04 14:11 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches, jason
Thanks for your helpful feedback. It has totally shaped my understanding.
While I was trying to develop other tests, as you suggested:
> It would be good to also test an explicit variable tmpl spec and
> an explicit spec of a member template of a class template.
I realized that for the case where we have a member function template
of a class template, and a specialization of the enclosing class only
(like below),
template <>
template <typename U>
void S<int>::f() {
// some constrained auto
}
When using S<int>::f<double>, DECL_TEMPLATE_INFO(fn) is non-zero, and
DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
So it means that the patch will extract DECL_TI_ARGS(fn) as
outer_targs, and it would be <int> <double> while the type of the
constrained auto will be as template <typename U> ... and will not be
dependent on the parameters of the enclosing class.
This means that again (outer_targs + targs) will have more depth than
auto_node levels.
This means that for the case where the function is not an explicit
specialization, but it is defined in an explicitly specialized scope,
the patch will not work.
I have thought of two ideas to fully solve the problem:
1. Trimming the full_targs by - missing_level, as you have mentioned.
2. Traversing the TI_TEMPLATE associated with different levels of
outer_targs, finding the first one that is
DECL_TEMPLATE_SPECIALIZATION, then trimming outer_targs by that point.
For the first idea,
> Another more context-unaware approach to fix this might be to only
> use the innermost level from 'full_targs' for satisfaction if
> TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> appeared in a context that doesn't have template parameters such as an
> explicit specialization or ordinary non-template function, and so
> only the level corresponding to the deduced type is needed for
> satisfaction.)
>
> Generalizing on that, another approach might be to handle missing_levels < 0
> by removing -missing_levels from full_targs via get_innermost_template_args.
> But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> case specifically.
I was unable to understand why you think that it might not handle
TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
reasoning as follows.
Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
For any case where missing_level < 0, it means that the type depends
on fewer levels than the template arguments used to materialize it.
This can only happen when the type is defined in an explicit
specialization scope. This explicit specialization might not occur in
its immediate scope.
Note that partial specialization (while changing the set of
parameters) cannot reduce the number of levels for the type.
Because of the fact that the enclosing scope of any explicit
specialization is explicitly specialized
(https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
on template parameters outside of its innermost explicit specialized
scope.
Assuming that there are no real missing levels, by removing those
levels, missing_level should be = 0. As a result, by roughly doing
if (missing_levels < 0) {
tree trimmed_full_args = get_innermost_template_args(full_targs,
TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
full_targs = trimmed_full_args;
}
in pt.cc:31262, where we calculate and check missing_levels, we would
be able to fix the errors.
Note that, for the case where there are real missing levels, we are
putting irrelevant template arguments for the missing levels instead
of make_tree_vec(0). By this change:
- If the type is independent of those missing levels: it works fine either way.
- If the type is dependent on those missing levels: Instead of raising
an ICE, the compiler exhibits undefined behavior.
Now, for the second idea, we need to do something like
int meaningful_levels = 0;
for (tree sc = fn;
DECL_TEMPLATE_INFO(sc) && !DECL_TEMPLATE_SPECIALIZATION(sc);
sc = DECL_TI_TEMPLATE(sc))
meaningful_levels ++;
outer_targs = get_innermost_template_args(DECL_TI_ARGS(fn), meaningful_levels);
in pt.cc:31238, instead of assigning DECL_TI_ARGS(fn) to outer_targs directly.
Note that we need to do the same thing in decl:8528 and maybe other places.
I would really appreciate your comments on these two ideas.
I will send another patch, applying the first idea in reply to this thread.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2] Fix auto deduction for template specialization scopes [PR114915]
2024-05-04 14:11 ` Seyed Sajad Kahani
@ 2024-05-04 15:15 ` Seyed Sajad Kahani
2024-05-06 18:46 ` Patrick Palka
0 siblings, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-05-04 15:15 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason, Seyed Sajad Kahani
The limitations of the initial patch (checking specializiation template usage), have been discussed.
> I realized that for the case where we have a member function template
> of a class template, and a specialization of the enclosing class only
> (like below),
>
> template <>
> template <typename U>
> void S<int>::f() {
> // some constrained auto
> }
>
> When using S<int>::f<double>, DECL_TEMPLATE_INFO(fn) is non-zero, and
> DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
> DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
> So it means that the patch will extract DECL_TI_ARGS(fn) as
> outer_targs, and it would be <int> <double> while the type of the
> constrained auto will be as template <typename U> ... and will not be
> dependent on the parameters of the enclosing class.
> This means that again (outer_targs + targs) will have more depth than
> auto_node levels.
> This means that for the case where the function is not an explicit
> specialization, but it is defined in an explicitly specialized scope,
> the patch will not work.
As described in more detail below, this patch attempts to resolve this issue by trimming full_targs.
> > Another more context-unaware approach to fix this might be to only
> > use the innermost level from 'full_targs' for satisfaction if
> > TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> > appeared in a context that doesn't have template parameters such as an
> > explicit specialization or ordinary non-template function, and so
> > only the level corresponding to the deduced type is needed for
> > satisfaction.)
> >
> > Generalizing on that, another approach might be to handle missing_levels < 0
> > by removing -missing_levels from full_targs via get_innermost_template_args.
> > But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> > case specifically.
>
> I was unable to understand why you think that it might not handle
> TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
> reasoning as follows.
>
> Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
> For any case where missing_level < 0, it means that the type depends
> on fewer levels than the template arguments used to materialize it.
> This can only happen when the type is defined in an explicit
> specialization scope. This explicit specialization might not occur in
> its immediate scope.
> Note that partial specialization (while changing the set of
> parameters) cannot reduce the number of levels for the type.
> Because of the fact that the enclosing scope of any explicit
> specialization is explicitly specialized
> (https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
> on template parameters outside of its innermost explicit specialized
> scope.
> Assuming that there are no real missing levels, by removing those
> levels, missing_level should be = 0. As a result, by roughly doing
>
> if (missing_levels < 0) {
> tree trimmed_full_args = get_innermost_template_args(full_targs,
> TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
> full_targs = trimmed_full_args;
> }
> in pt.cc:31262, where we calculate and check missing_levels, we would
> be able to fix the errors.
> Note that, for the case where there are real missing levels, we are
> putting irrelevant template arguments for the missing levels instead
> of make_tree_vec(0). By this change:
> - If the type is independent of those missing levels: it works fine either way.
> - If the type is dependent on those missing levels: Instead of raising
> an ICE, the compiler exhibits undefined behavior.
---
gcc/cp/pt.cc | 14 ++++++--
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
4 files changed, 78 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3b2106dd3..bdf03a1a7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree init)
OUTER_TARGS is used during template argument deduction (context == adc_unify)
to properly substitute the result. It's also used in the adc_unify and
adc_requirement contexts to communicate the necessary template arguments
- to satisfaction. OUTER_TARGS is ignored in other contexts.
+ to satisfaction. OUTER_TARGS will be used for other contexts if it is a
+ function scope deduction. Otherwise it is ignored.
Additionally for adc_unify contexts TMPL is the template for which TYPE
is a template parameter type.
@@ -31260,8 +31261,15 @@ do_auto_deduction (tree type, tree init, tree auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- - TMPL_ARGS_DEPTH (full_targs)))
+ int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
+ - TMPL_ARGS_DEPTH (full_targs));
+ if (missing_levels < 0)
+ {
+ tree trimmed_full_args = get_innermost_template_args(full_targs,
+ TEMPLATE_TYPE_ORIG_LEVEL (auto_node));
+ full_targs = trimmed_full_args;
+ }
+ if (missing_levels > 0)
{
tree dummy_levels = make_tree_vec (missing_levels);
for (int i = 0; i < missing_levels; ++i)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b4f73f407
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,15 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+int main() {
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
--
2.45.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] Fix auto deduction for template specialization scopes [PR114915]
2024-05-04 15:15 ` [PATCH v2] Fix auto deduction for template specialization scopes [PR114915] Seyed Sajad Kahani
@ 2024-05-06 18:46 ` Patrick Palka
2024-05-10 12:43 ` Seyed Sajad Kahani
2024-05-10 12:47 ` [PATCH v3] " Seyed Sajad Kahani
0 siblings, 2 replies; 25+ messages in thread
From: Patrick Palka @ 2024-05-06 18:46 UTC (permalink / raw)
To: Seyed Sajad Kahani; +Cc: gcc-patches, ppalka, jason
On Sat, 4 May 2024, Seyed Sajad Kahani wrote:
> The limitations of the initial patch (checking specializiation template usage), have been discussed.
>
> > I realized that for the case where we have a member function template
> > of a class template, and a specialization of the enclosing class only
> > (like below),
> >
> > template <>
> > template <typename U>
> > void S<int>::f() {
> > // some constrained auto
> > }
> >
> > When using S<int>::f<double>, DECL_TEMPLATE_INFO(fn) is non-zero, and
> > DECL_TEMPLATE_SPECIALIZATION(fn) is zero, while
> > DECL_TEMPLATE_SPECIALIZATION(DECL_TI_TEMPLATE(fn)) is non-zero.
> > So it means that the patch will extract DECL_TI_ARGS(fn) as
> > outer_targs, and it would be <int> <double> while the type of the
> > constrained auto will be as template <typename U> ... and will not be
> > dependent on the parameters of the enclosing class.
> > This means that again (outer_targs + targs) will have more depth than
> > auto_node levels.
> > This means that for the case where the function is not an explicit
> > specialization, but it is defined in an explicitly specialized scope,
> > the patch will not work.
Ah yes, good point! This demonstrates that it doesn't suffice to
handle the TEMPLATE_TYPE_ORIG_LEVEL == 1 case contrary to what I
suggested earlier.
>
> As described in more detail below, this patch attempts to resolve this issue by trimming full_targs.
>
> > > Another more context-unaware approach to fix this might be to only
> > > use the innermost level from 'full_targs' for satisfaction if
> > > TEMPLATE_TYPE_ORIG_LEVEL is 1 (which means this constrained auto
> > > appeared in a context that doesn't have template parameters such as an
> > > explicit specialization or ordinary non-template function, and so
> > > only the level corresponding to the deduced type is needed for
> > > satisfaction.)
> > >
> > > Generalizing on that, another approach might be to handle missing_levels < 0
> > > by removing -missing_levels from full_targs via get_innermost_template_args.
> > > But AFAICT it should suffice to handle the TEMPLATE_TYPE_ORIG_LEVEL == 1
> > > case specifically.
> >
> > I was unable to understand why you think that it might not handle
> > TEMPLATE_TYPE_ORIG_LEVEL > 1 cases, so I tried to formulate my
> > reasoning as follows.
Yes, sorry about that misleading suggestion.
> >
> > Assuming contexts adc_variable_type, adc_return_type, adc_decomp_type:
> > For any case where missing_level < 0, it means that the type depends
> > on fewer levels than the template arguments used to materialize it.
> > This can only happen when the type is defined in an explicit
> > specialization scope. This explicit specialization might not occur in
> > its immediate scope.
> > Note that partial specialization (while changing the set of
> > parameters) cannot reduce the number of levels for the type.
> > Because of the fact that the enclosing scope of any explicit
> > specialization is explicitly specialized
> > (https://eel.is/c++draft/temp.expl.spec#16), the type will not depend
> > on template parameters outside of its innermost explicit specialized
> > scope.
> > Assuming that there are no real missing levels, by removing those
> > levels, missing_level should be = 0. As a result, by roughly doing
> >
> > if (missing_levels < 0) {
> > tree trimmed_full_args = get_innermost_template_args(full_targs,
> > TEMPLATE_TYPE_ORIG_LEVEL(auto_node));
> > full_targs = trimmed_full_args;
> > }
> > in pt.cc:31262, where we calculate and check missing_levels, we would
> > be able to fix the errors.
> > Note that, for the case where there are real missing levels, we are
> > putting irrelevant template arguments for the missing levels instead
> > of make_tree_vec(0). By this change:
> > - If the type is independent of those missing levels: it works fine either way.
> > - If the type is dependent on those missing levels: Instead of raising
> > an ICE, the compiler exhibits undefined behavior.
Makes sense.
> ---
> gcc/cp/pt.cc | 14 ++++++--
> .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
> .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
> .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
> 4 files changed, 78 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..bdf03a1a7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31044,7 +31044,8 @@ unparenthesized_id_or_class_member_access_p (tree init)
> OUTER_TARGS is used during template argument deduction (context == adc_unify)
> to properly substitute the result. It's also used in the adc_unify and
> adc_requirement contexts to communicate the necessary template arguments
> - to satisfaction. OUTER_TARGS is ignored in other contexts.
> + to satisfaction. OUTER_TARGS will be used for other contexts if it is a
> + function scope deduction. Otherwise it is ignored.
The use of OUTER_TARGS for satisfaction is already generically covered
in the last paragraph of the function comment:
For partial-concept-ids, extra args from OUTER_TARGS, TMPL and the current
scope may be appended to the list of deduced template arguments prior to
determining constraint satisfaction as appropriate.
So this change is probably unnecessary.
>
> Additionally for adc_unify contexts TMPL is the template for which TYPE
> is a template parameter type.
> @@ -31260,8 +31261,15 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> these missing levels, but this hack otherwise allows us to handle a
> large subset of possible constraints (including all non-dependent
> constraints). */
> - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> + int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> + - TMPL_ARGS_DEPTH (full_targs));
> + if (missing_levels < 0)
> + {
> + tree trimmed_full_args = get_innermost_template_args(full_targs,
> + TEMPLATE_TYPE_ORIG_LEVEL (auto_node));
> + full_targs = trimmed_full_args;
> + }
> + if (missing_levels > 0)
Looks correct to me! (Though in order to be consistent the GNU coding
style while respecting the 80-character line limit, this should be
formatted as
if (missing_levels < 0)
{
tree trimmed_full_args = get_innermost_template_args
(full_targs, TEMPLATE_TYPE_ORIG_LEVEL (auto_node));
full_targs = trimmed_full_args;
}
We could also/instead consider defining
int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
int have = TMPL_ARGS_DEPTH (full_targs);
and express the logic in terms of these instead of the possibly
negative 'missing_levels'. The 'want < have' case could have a comment
mentioning that this occurs for a constrained auto within an explicit
specialization.)
Note that GCC doesn't currently support explicit specializations within
template scope, e.g.
template<class T>
struct A {
template<class U> struct B { };
template<> struct B<int> {
static inline C auto x = 1;
};
};
which might otherwise complicate things here. But since we don't yet
support it we don't have to worry about this case :) I think stripping
the outermost extraneous levels as your patch does will currently always
do the right thing for us. But in the above example which we don't
support, we probably would need to strip _innermost_ extraneous levels,
i.e. the <int>.
> {
> tree dummy_levels = make_tree_vec (missing_levels);
> for (int i = 0; i < missing_levels; ++i)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 000000000..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T>
> +concept C = __is_same(T, int);
> +
> +template<typename T>
> +void f() {
> +}
> +
> +template<>
> +void f<int>() {
> + C auto x = 1;
> +}
> +
> +int main() {
> + f<int>();
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 000000000..b4f73f407
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,15 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +int x = 0;
> +
> +template<>
> +C<double> auto x<double> = 1.0;
> +
> +int main() {
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 000000000..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +struct A
> +{
> + template<typename U>
> + void f() {
> + }
> +};
> +
> +template<>
> +template<>
> +void A<int>::f<int>() {
> + C<int> auto x = 1;
> +}
> +
> +template<>
> +template<typename U>
> +void A<bool>::f() {
> + C<int> auto x = 1;
> +}
> +
> +int main() {
> + A<bool> a;
> + a.f<char>();
> + A<int> b;
> + b.f<int>();
> + return 0;
> +}
Thanks for these extra testcases!
> --
> 2.45.0
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] Fix auto deduction for template specialization scopes [PR114915]
2024-05-06 18:46 ` Patrick Palka
@ 2024-05-10 12:43 ` Seyed Sajad Kahani
2024-05-10 12:47 ` [PATCH v3] " Seyed Sajad Kahani
1 sibling, 0 replies; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-05-10 12:43 UTC (permalink / raw)
To: gcc-patches; +Cc: Patrick Palka, jason
Thanks for your suggestions. I will apply them in the upcoming patch (v3).
On Mon, May 6, 2024 at 7:46 PM Patrick Palka <ppalka@redhat.com> wrote:
> We could also/instead consider defining
>
> int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> int have = TMPL_ARGS_DEPTH (full_targs);
>
> and express the logic in terms of these instead of the possibly
> negative 'missing_levels'. The 'want < have' case could have a comment
> mentioning that this occurs for a constrained auto within an explicit
> specialization.)
I converted missing_levels into want and have variables. Additionally, I
added an assertion to explicitly state that our trimming logic assumes the
context to be one of adc_variable_type, adc_return_type, or adc_decomp_type.
> > > Note that, for the case where there are real missing levels, we are
> > > putting irrelevant template arguments for the missing levels instead
> > > of make_tree_vec(0). By this change:
> > > - If the type is independent of those missing levels: it works fine either way.
> > > - If the type is dependent on those missing levels: Instead of raising
> > > an ICE, the compiler exhibits undefined behavior.
>
> Makes sense.
For the record, I have looked into the history of this hack to find out in
which scenarios we may have to deal with missing levels.
https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=b49d23f3e238c08bdbc5b892b2ed0a57b5f5caf9
As far as I can understand, it was limited to the adc_unify context at that
time, but it might have been changed since then. Since I was not sure about
it, I have not added an assertion for this case.
Many thanks!
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v3] Fix auto deduction for template specialization scopes [PR114915]
2024-05-06 18:46 ` Patrick Palka
2024-05-10 12:43 ` Seyed Sajad Kahani
@ 2024-05-10 12:47 ` Seyed Sajad Kahani
2024-05-15 15:07 ` [PATCH v3] c++: " Patrick Palka
1 sibling, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-05-10 12:47 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, Seyed Sajad Kahani
This patch resolves PR114915 by replacing the logic that fills in the missing levels in do_auto_deduction in cp/pt.cc.
The new approach now trims targs if the depth of targs is deeper than desired (this will only happen in specific contexts), and still fills targs with empty layers if it has fewer depths than expected.
---
gcc/cp/pt.cc | 20 ++++++++---
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
4 files changed, 83 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3b2106dd3..479b2a5bd 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
full_targs = add_outermost_template_args (tmpl, full_targs);
full_targs = add_to_template_args (full_targs, targs);
+ int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
+ int have = TMPL_ARGS_DEPTH (full_targs);
+
+ if (want < have)
+ {
+ // if a constrained auto is declared in an explicit specialization
+ gcc_assert (context == adc_variable_type || context == adc_return_type
+ || context == adc_decomp_type);
+ tree trimmed_full_args = get_innermost_template_args
+ (full_targs, want);
+ full_targs = trimmed_full_args;
+ }
+
/* HACK: Compensate for callers not always communicating all levels of
outer template arguments by filling in the outermost missing levels
with dummy levels before checking satisfaction. We'll still crash
@@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- - TMPL_ARGS_DEPTH (full_targs)))
+ if (want > have)
{
- tree dummy_levels = make_tree_vec (missing_levels);
- for (int i = 0; i < missing_levels; ++i)
+ tree dummy_levels = make_tree_vec (want - have);
+ for (int i = 0; i < want - have; ++i)
TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
full_targs = add_to_template_args (dummy_levels, full_targs);
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b4f73f407
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,15 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+int main() {
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
--
2.45.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] c++: Fix auto deduction for template specialization scopes [PR114915]
2024-05-10 12:47 ` [PATCH v3] " Seyed Sajad Kahani
@ 2024-05-15 15:07 ` Patrick Palka
2024-05-15 15:09 ` Patrick Palka
0 siblings, 1 reply; 25+ messages in thread
From: Patrick Palka @ 2024-05-15 15:07 UTC (permalink / raw)
To: Seyed Sajad Kahani; +Cc: gcc-patches, ppalka, jaon
On Fri, 10 May 2024, Seyed Sajad Kahani wrote:
> This patch resolves PR114915 by replacing the logic that fills in the missing levels in do_auto_deduction in cp/pt.cc.
> The new approach now trims targs if the depth of targs is deeper than desired (this will only happen in specific contexts), and still fills targs with empty layers if it has fewer depths than expected.
The logic looks good to me, thanks! Note that as per
https://gcc.gnu.org/contribute.html patches need a ChangeLog entry in
the commit message, for example let's use:
PR c++/114915
gcc/cp/ChangeLog:
* pt.cc (do_auto_deduction): Handle excess outer template
arguments during constrained auto satisfaction.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.
Jason, what do you think?
> ---
> gcc/cp/pt.cc | 20 ++++++++---
> .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
> .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
> .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
> 4 files changed, 83 insertions(+), 4 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 3b2106dd3..479b2a5bd 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> full_targs = add_outermost_template_args (tmpl, full_targs);
> full_targs = add_to_template_args (full_targs, targs);
>
> + int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> + int have = TMPL_ARGS_DEPTH (full_targs);
> +
> + if (want < have)
> + {
> + // if a constrained auto is declared in an explicit specialization
> + gcc_assert (context == adc_variable_type || context == adc_return_type
> + || context == adc_decomp_type);
> + tree trimmed_full_args = get_innermost_template_args
> + (full_targs, want);
> + full_targs = trimmed_full_args;
> + }
> +
> /* HACK: Compensate for callers not always communicating all levels of
> outer template arguments by filling in the outermost missing levels
> with dummy levels before checking satisfaction. We'll still crash
> @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> these missing levels, but this hack otherwise allows us to handle a
> large subset of possible constraints (including all non-dependent
> constraints). */
> - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> + if (want > have)
> {
> - tree dummy_levels = make_tree_vec (missing_levels);
> - for (int i = 0; i < missing_levels; ++i)
> + tree dummy_levels = make_tree_vec (want - have);
> + for (int i = 0; i < want - have; ++i)
> TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> full_targs = add_to_template_args (dummy_levels, full_targs);
> }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 000000000..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T>
> +concept C = __is_same(T, int);
> +
> +template<typename T>
> +void f() {
> +}
> +
> +template<>
> +void f<int>() {
> + C auto x = 1;
> +}
> +
> +int main() {
> + f<int>();
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 000000000..b4f73f407
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,15 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +int x = 0;
> +
> +template<>
> +C<double> auto x<double> = 1.0;
> +
> +int main() {
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 000000000..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +struct A
> +{
> + template<typename U>
> + void f() {
> + }
> +};
> +
> +template<>
> +template<>
> +void A<int>::f<int>() {
> + C<int> auto x = 1;
> +}
> +
> +template<>
> +template<typename U>
> +void A<bool>::f() {
> + C<int> auto x = 1;
> +}
> +
> +int main() {
> + A<bool> a;
> + a.f<char>();
> + A<int> b;
> + b.f<int>();
> + return 0;
> +}
> --
> 2.45.0
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] c++: Fix auto deduction for template specialization scopes [PR114915]
2024-05-15 15:07 ` [PATCH v3] c++: " Patrick Palka
@ 2024-05-15 15:09 ` Patrick Palka
2024-05-15 17:27 ` [PATCH v4] c++: fix constained auto deduction in templ spec " Seyed Sajad Kahani
0 siblings, 1 reply; 25+ messages in thread
From: Patrick Palka @ 2024-05-15 15:09 UTC (permalink / raw)
To: Patrick Palka; +Cc: Seyed Sajad Kahani, gcc-patches, jason
On Wed, 15 May 2024, Patrick Palka wrote:
>
> On Fri, 10 May 2024, Seyed Sajad Kahani wrote:
>
> > This patch resolves PR114915 by replacing the logic that fills in the missing levels in do_auto_deduction in cp/pt.cc.
> > The new approach now trims targs if the depth of targs is deeper than desired (this will only happen in specific contexts), and still fills targs with empty layers if it has fewer depths than expected.
>
> The logic looks good to me, thanks! Note that as per
> https://gcc.gnu.org/contribute.html patches need a ChangeLog entry in
> the commit message, for example let's use:
>
> PR c++/114915
>
> gcc/cp/ChangeLog:
>
> * pt.cc (do_auto_deduction): Handle excess outer template
> arguments during constrained auto satisfaction.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/concepts-placeholder14.C: New test.
> * g++.dg/cpp2a/concepts-placeholder15.C: New test.
> * g++.dg/cpp2a/concepts-placeholder16.C: New test.
>
> Jason, what do you think?
... now sent to the correct email, sorry for the spam
>
> > ---
> > gcc/cp/pt.cc | 20 ++++++++---
> > .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
> > .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
> > .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
> > 4 files changed, 83 insertions(+), 4 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> >
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 3b2106dd3..479b2a5bd 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> > full_targs = add_outermost_template_args (tmpl, full_targs);
> > full_targs = add_to_template_args (full_targs, targs);
> >
> > + int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> > + int have = TMPL_ARGS_DEPTH (full_targs);
> > +
> > + if (want < have)
> > + {
> > + // if a constrained auto is declared in an explicit specialization
> > + gcc_assert (context == adc_variable_type || context == adc_return_type
> > + || context == adc_decomp_type);
> > + tree trimmed_full_args = get_innermost_template_args
> > + (full_targs, want);
> > + full_targs = trimmed_full_args;
> > + }
> > +
> > /* HACK: Compensate for callers not always communicating all levels of
> > outer template arguments by filling in the outermost missing levels
> > with dummy levels before checking satisfaction. We'll still crash
> > @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> > these missing levels, but this hack otherwise allows us to handle a
> > large subset of possible constraints (including all non-dependent
> > constraints). */
> > - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> > - - TMPL_ARGS_DEPTH (full_targs)))
> > + if (want > have)
> > {
> > - tree dummy_levels = make_tree_vec (missing_levels);
> > - for (int i = 0; i < missing_levels; ++i)
> > + tree dummy_levels = make_tree_vec (want - have);
> > + for (int i = 0; i < want - have; ++i)
> > TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> > full_targs = add_to_template_args (dummy_levels, full_targs);
> > }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > new file mode 100644
> > index 000000000..fcdbd7608
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > @@ -0,0 +1,19 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<typename T>
> > +concept C = __is_same(T, int);
> > +
> > +template<typename T>
> > +void f() {
> > +}
> > +
> > +template<>
> > +void f<int>() {
> > + C auto x = 1;
> > +}
> > +
> > +int main() {
> > + f<int>();
> > + return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > new file mode 100644
> > index 000000000..b4f73f407
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > @@ -0,0 +1,15 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<typename T, typename U>
> > +concept C = __is_same(T, U);
> > +
> > +template<typename T>
> > +int x = 0;
> > +
> > +template<>
> > +C<double> auto x<double> = 1.0;
> > +
> > +int main() {
> > + return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > new file mode 100644
> > index 000000000..f808ef1b6
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > @@ -0,0 +1,33 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<typename T, typename U>
> > +concept C = __is_same(T, U);
> > +
> > +template<typename T>
> > +struct A
> > +{
> > + template<typename U>
> > + void f() {
> > + }
> > +};
> > +
> > +template<>
> > +template<>
> > +void A<int>::f<int>() {
> > + C<int> auto x = 1;
> > +}
> > +
> > +template<>
> > +template<typename U>
> > +void A<bool>::f() {
> > + C<int> auto x = 1;
> > +}
> > +
> > +int main() {
> > + A<bool> a;
> > + a.f<char>();
> > + A<int> b;
> > + b.f<int>();
> > + return 0;
> > +}
> > --
> > 2.45.0
> >
> >
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v4] c++: fix constained auto deduction in templ spec scopes [PR114915]
2024-05-15 15:09 ` Patrick Palka
@ 2024-05-15 17:27 ` Seyed Sajad Kahani
2024-05-22 20:30 ` Jason Merrill
0 siblings, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-05-15 17:27 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason, Seyed Sajad Kahani
This patch resolves PR114915 by replacing the logic that fills in the
missing levels in do_auto_deduction in cp/pt.cc.
The new approach now trims targs if the depth of targs is deeper than desired
(this will only happen in specific contexts), and still fills targs with empty
layers if it has fewer depths than expected.
PR c++/114915
gcc/cp/ChangeLog:
* pt.cc (do_auto_deduction): Handle excess outer template
arguments during constrained auto satisfaction.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.
---
gcc/cp/pt.cc | 20 ++++++++---
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
4 files changed, 83 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e9..ecfda67aa 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
full_targs = add_outermost_template_args (tmpl, full_targs);
full_targs = add_to_template_args (full_targs, targs);
+ int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
+ int have = TMPL_ARGS_DEPTH (full_targs);
+
+ if (want < have)
+ {
+ // if a constrained auto is declared in an explicit specialization
+ gcc_assert (context == adc_variable_type || context == adc_return_type
+ || context == adc_decomp_type);
+ tree trimmed_full_args = get_innermost_template_args
+ (full_targs, want);
+ full_targs = trimmed_full_args;
+ }
+
/* HACK: Compensate for callers not always communicating all levels of
outer template arguments by filling in the outermost missing levels
with dummy levels before checking satisfaction. We'll still crash
@@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- - TMPL_ARGS_DEPTH (full_targs)))
+ if (want > have)
{
- tree dummy_levels = make_tree_vec (missing_levels);
- for (int i = 0; i < missing_levels; ++i)
+ tree dummy_levels = make_tree_vec (want - have);
+ for (int i = 0; i < want - have; ++i)
TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
full_targs = add_to_template_args (dummy_levels, full_targs);
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b4f73f407
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,15 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+int main() {
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
--
2.45.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Fix auto deduction for template specialization scopes [114915].
2024-05-01 22:52 [PATCH] Fix auto deduction for template specialization scopes [114915] Seyed Sajad Kahani
2024-05-03 16:24 ` Patrick Palka
@ 2024-05-22 15:41 ` Jason Merrill
2024-05-22 16:48 ` Patrick Palka
1 sibling, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2024-05-22 15:41 UTC (permalink / raw)
To: Seyed Sajad Kahani, gcc-patches
Thanks for the patch!
Please review https://gcc.gnu.org/contribute.html for more details of
the format patches should have. In particular, you don't seem to have a
copyright assignment on file with the FSF, so you'll need to either do
that or certify that the contribution is under the DCO.
Also, you need a component tag (c++:) in the subject line, and ChangeLog
entries in the commit message. Note what contribute.html says about git
gcc-commit-mklog, which makes that a lot simpler.
On 5/1/24 18:52, Seyed Sajad Kahani wrote:
> When deducing auto for `adc_return_type`, `adc_variable_type`, and `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost template arguments to be used for satisfaction. This is done by one of the following, depending on the scope:
>
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other conditions) for non-function scope variable declaration deductions (decl.cc:8527).
>
> Then, we do not retrieve the deeper layers of the template arguments; instead, we fill the missing levels with dummy levels (pt.cc:31260).
>
> The problem (that is shown in PR114915) is that we do not consider the case where the deduction happens in a template specialization scope. In this case, the type is not dependent on the outermost template arguments (which are the specialization arguments). Yet, we still resolve the outermost template arguments, and then the number of layers in the template arguments exceeds the number of levels in the type. This causes the missing levels to be negative. This leads to the rejection of valid code and ICEs (like segfault) in the release mode. In the debug mode, it is possible to show as an assertion failure (when creating a tree_vec with a negative size).
> The code that generates the issue is added to the test suite as `g++.dg/cpp2a/concepts-placeholder14.C`.
This testcase could use more cases, like variable template
specialization (both full and partial) and member functions where not
all enclosing classes are fully specialized.
> This patch fixes the issue by checking that the template usage, whose arguments are going to be used for satisfaction, is not a partial or explicit specialization (and therefore it is an implicit or explicit instantiation). This check is done in the two only places that affect the `outer_targs` for the mentioned contexts.
It seems like we want a function to use instead of DECL_TI_ARGS to get
the args for parameters that are actually in scope in the definition
that we're substituting into. In the case of a full specialization,
that would be NULL_TREE, but it's more complicated for partial
specializations.
This function should probably go after outer_template_args in pt.cc.
> One might ask why this is not implemented as a simple `missing_level > 0` check. The reason is that the recovery from the negative `missing_levels` will not be easy, and it is not clear how to recover from it. Therefore, it is better to prevent it from happening.
But you still have that check in the patch. Would it be better as an
assert?
Thanks,
Jason
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Fix auto deduction for template specialization scopes [114915].
2024-05-22 15:41 ` [PATCH] Fix auto deduction for template specialization scopes [114915] Jason Merrill
@ 2024-05-22 16:48 ` Patrick Palka
2024-05-22 17:32 ` Jason Merrill
0 siblings, 1 reply; 25+ messages in thread
From: Patrick Palka @ 2024-05-22 16:48 UTC (permalink / raw)
To: Jason Merrill; +Cc: Seyed Sajad Kahani, gcc-patches
On Wed, 22 May 2024, Jason Merrill wrote:
> Thanks for the patch!
>
> Please review https://gcc.gnu.org/contribute.html for more details of the
> format patches should have. In particular, you don't seem to have a copyright
> assignment on file with the FSF, so you'll need to either do that or certify
> that the contribution is under the DCO.
>
> Also, you need a component tag (c++:) in the subject line, and ChangeLog
> entries in the commit message. Note what contribute.html says about git
> gcc-commit-mklog, which makes that a lot simpler.
>
> On 5/1/24 18:52, Seyed Sajad Kahani wrote:
> > When deducing auto for `adc_return_type`, `adc_variable_type`, and
> > `adc_decomp_type` contexts (at the usage time), we try to resolve the
> > outermost template arguments to be used for satisfaction. This is done by
> > one of the following, depending on the scope:
> >
> > 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
> > extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> > 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with
> > other conditions) for non-function scope variable declaration deductions
> > (decl.cc:8527).
> >
> > Then, we do not retrieve the deeper layers of the template arguments;
> > instead, we fill the missing levels with dummy levels (pt.cc:31260).
> >
> > The problem (that is shown in PR114915) is that we do not consider the case
> > where the deduction happens in a template specialization scope. In this
> > case, the type is not dependent on the outermost template arguments (which
> > are the specialization arguments). Yet, we still resolve the outermost
> > template arguments, and then the number of layers in the template arguments
> > exceeds the number of levels in the type. This causes the missing levels to
> > be negative. This leads to the rejection of valid code and ICEs (like
> > segfault) in the release mode. In the debug mode, it is possible to show as
> > an assertion failure (when creating a tree_vec with a negative size).
> > The code that generates the issue is added to the test suite as
> > `g++.dg/cpp2a/concepts-placeholder14.C`.
>
> This testcase could use more cases, like variable template specialization
> (both full and partial) and member functions where not all enclosing classes
> are fully specialized.
Note I think the latest version of the patch is
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651805.html
which has more test coverage and takes a more context oblivious approach
that keeps the innermost arguments if there's an excess, based on some
earlier discussion e.g.
https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650834.html
This should do the right thing at least until we implement explicit
specializations in template scope (CWG 727)
>
> > This patch fixes the issue by checking that the template usage, whose
> > arguments are going to be used for satisfaction, is not a partial or
> > explicit specialization (and therefore it is an implicit or explicit
> > instantiation). This check is done in the two only places that affect the
> > `outer_targs` for the mentioned contexts.
>
> It seems like we want a function to use instead of DECL_TI_ARGS to get the
> args for parameters that are actually in scope in the definition that we're
> substituting into. In the case of a full specialization, that would be
> NULL_TREE, but it's more complicated for partial specializations.
>
> This function should probably go after outer_template_args in pt.cc.
>
> > One might ask why this is not implemented as a simple `missing_level > 0`
> > check. The reason is that the recovery from the negative `missing_levels`
> > will not be easy, and it is not clear how to recover from it. Therefore, it
> > is better to prevent it from happening.
>
> But you still have that check in the patch. Would it be better as an assert?
>
> Thanks,
> Jason
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Fix auto deduction for template specialization scopes [114915].
2024-05-22 16:48 ` Patrick Palka
@ 2024-05-22 17:32 ` Jason Merrill
0 siblings, 0 replies; 25+ messages in thread
From: Jason Merrill @ 2024-05-22 17:32 UTC (permalink / raw)
To: Patrick Palka; +Cc: Seyed Sajad Kahani, gcc-patches
On 5/22/24 12:48, Patrick Palka wrote:
> On Wed, 22 May 2024, Jason Merrill wrote:
>
>> Thanks for the patch!
>>
>> Please review https://gcc.gnu.org/contribute.html for more details of the
>> format patches should have. In particular, you don't seem to have a copyright
>> assignment on file with the FSF, so you'll need to either do that or certify
>> that the contribution is under the DCO.
>>
>> Also, you need a component tag (c++:) in the subject line, and ChangeLog
>> entries in the commit message. Note what contribute.html says about git
>> gcc-commit-mklog, which makes that a lot simpler.
>>
>> On 5/1/24 18:52, Seyed Sajad Kahani wrote:
>>> When deducing auto for `adc_return_type`, `adc_variable_type`, and
>>> `adc_decomp_type` contexts (at the usage time), we try to resolve the
>>> outermost template arguments to be used for satisfaction. This is done by
>>> one of the following, depending on the scope:
>>>
>>> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
>>> extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
>>> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with
>>> other conditions) for non-function scope variable declaration deductions
>>> (decl.cc:8527).
>>>
>>> Then, we do not retrieve the deeper layers of the template arguments;
>>> instead, we fill the missing levels with dummy levels (pt.cc:31260).
>>>
>>> The problem (that is shown in PR114915) is that we do not consider the case
>>> where the deduction happens in a template specialization scope. In this
>>> case, the type is not dependent on the outermost template arguments (which
>>> are the specialization arguments). Yet, we still resolve the outermost
>>> template arguments, and then the number of layers in the template arguments
>>> exceeds the number of levels in the type. This causes the missing levels to
>>> be negative. This leads to the rejection of valid code and ICEs (like
>>> segfault) in the release mode. In the debug mode, it is possible to show as
>>> an assertion failure (when creating a tree_vec with a negative size).
>>> The code that generates the issue is added to the test suite as
>>> `g++.dg/cpp2a/concepts-placeholder14.C`.
>>
>> This testcase could use more cases, like variable template specialization
>> (both full and partial) and member functions where not all enclosing classes
>> are fully specialized.
>
> Note I think the latest version of the patch is
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651805.html
Oops, thanks!
> which has more test coverage and takes a more context oblivious approach
> that keeps the innermost arguments if there's an excess, based on some
> earlier discussion e.g.
> https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650834.html
> This should do the right thing at least until we implement explicit
> specializations in template scope (CWG 727)
>
>>
>>> This patch fixes the issue by checking that the template usage, whose
>>> arguments are going to be used for satisfaction, is not a partial or
>>> explicit specialization (and therefore it is an implicit or explicit
>>> instantiation). This check is done in the two only places that affect the
>>> `outer_targs` for the mentioned contexts.
>>
>> It seems like we want a function to use instead of DECL_TI_ARGS to get the
>> args for parameters that are actually in scope in the definition that we're
>> substituting into. In the case of a full specialization, that would be
>> NULL_TREE, but it's more complicated for partial specializations.
>>
>> This function should probably go after outer_template_args in pt.cc.
>>
>>> One might ask why this is not implemented as a simple `missing_level > 0`
>>> check. The reason is that the recovery from the negative `missing_levels`
>>> will not be easy, and it is not clear how to recover from it. Therefore, it
>>> is better to prevent it from happening.
>>
>> But you still have that check in the patch. Would it be better as an assert?
>>
>> Thanks,
>> Jason
>>
>>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] c++: fix constained auto deduction in templ spec scopes [PR114915]
2024-05-15 17:27 ` [PATCH v4] c++: fix constained auto deduction in templ spec " Seyed Sajad Kahani
@ 2024-05-22 20:30 ` Jason Merrill
2024-06-14 14:15 ` sska1377
2024-06-14 14:18 ` [PATCH v5] " Seyed Sajad Kahani
0 siblings, 2 replies; 25+ messages in thread
From: Jason Merrill @ 2024-05-22 20:30 UTC (permalink / raw)
To: Seyed Sajad Kahani, gcc-patches; +Cc: ppalka
OK, on the right patch this time I hope.
Looks like you still need either FSF copyright assignment or DCO
certification per https://gcc.gnu.org/contribute.html#legal
On 5/15/24 13:27, Seyed Sajad Kahani wrote:
> This patch resolves PR114915 by replacing the logic that fills in the
> missing levels in do_auto_deduction in cp/pt.cc.
I miss the text in your original patch that explained the problem more.
> The new approach now trims targs if the depth of targs is deeper than desired
> (this will only happen in specific contexts), and still fills targs with empty
> layers if it has fewer depths than expected.
>
> PR c++/114915
This line needs to start with a tab.
> gcc/cp/ChangeLog:
>
> * pt.cc (do_auto_deduction): Handle excess outer template
> arguments during constrained auto satisfaction.
This one, too. These issues are flagged by git gcc-verify, and are
easier to avoid with git gcc-commit-mklog.
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/concepts-placeholder14.C: New test.
> * g++.dg/cpp2a/concepts-placeholder15.C: New test.
This test still needs a variable template partial specialization.
A few coding style nits below.
> * g++.dg/cpp2a/concepts-placeholder16.C: New test.
> ---
> gcc/cp/pt.cc | 20 ++++++++---
> .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
> .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
> .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
> 4 files changed, 83 insertions(+), 4 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 32640f8e9..ecfda67aa 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> full_targs = add_outermost_template_args (tmpl, full_targs);
> full_targs = add_to_template_args (full_targs, targs);
>
> + int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> + int have = TMPL_ARGS_DEPTH (full_targs);
> +
> + if (want < have)
> + {
> + // if a constrained auto is declared in an explicit specialization
We generally use C-style /* */ comments, that start with a capital
letter and end with a period.
> + gcc_assert (context == adc_variable_type || context == adc_return_type
> + || context == adc_decomp_type);
The || should line up with the 'c' on the previous line.
> + tree trimmed_full_args = get_innermost_template_args
> + (full_targs, want);
We try to avoid having arguments to the left of the function name; here
I'd start the new line with the = instead.
> + full_targs = trimmed_full_args;
> + }
> +
Unnecessary tab on this line.
> /* HACK: Compensate for callers not always communicating all levels of
> outer template arguments by filling in the outermost missing levels
> with dummy levels before checking satisfaction. We'll still crash
> @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> these missing levels, but this hack otherwise allows us to handle a
> large subset of possible constraints (including all non-dependent
> constraints). */
> - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> + if (want > have)
> {
> - tree dummy_levels = make_tree_vec (missing_levels);
> - for (int i = 0; i < missing_levels; ++i)
> + tree dummy_levels = make_tree_vec (want - have);
> + for (int i = 0; i < want - have; ++i)
> TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> full_targs = add_to_template_args (dummy_levels, full_targs);
> }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 000000000..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T>
> +concept C = __is_same(T, int);
> +
> +template<typename T>
> +void f() {
> +}
> +
> +template<>
> +void f<int>() {
> + C auto x = 1;
> +}
> +
> +int main() {
> + f<int>();
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 000000000..b4f73f407
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,15 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +int x = 0;
> +
> +template<>
> +C<double> auto x<double> = 1.0;
> +
> +int main() {
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 000000000..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +struct A
> +{
> + template<typename U>
> + void f() {
> + }
> +};
> +
> +template<>
> +template<>
> +void A<int>::f<int>() {
> + C<int> auto x = 1;
> +}
> +
> +template<>
> +template<typename U>
> +void A<bool>::f() {
> + C<int> auto x = 1;
> +}
> +
> +int main() {
> + A<bool> a;
> + a.f<char>();
> + A<int> b;
> + b.f<int>();
> + return 0;
> +}
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] c++: fix constained auto deduction in templ spec scopes [PR114915]
2024-05-22 20:30 ` Jason Merrill
@ 2024-06-14 14:15 ` sska1377
2024-06-14 14:18 ` [PATCH v5] " Seyed Sajad Kahani
1 sibling, 0 replies; 25+ messages in thread
From: sska1377 @ 2024-06-14 14:15 UTC (permalink / raw)
To: Jason Merrill, gcc-patches; +Cc: ppalka
On Wed, 2024-05-22 at 16:30 -0400, Jason Merrill wrote:
> OK, on the right patch this time I hope.
>
> Looks like you still need either FSF copyright assignment or DCO
> certification per https://gcc.gnu.org/contribute.html#legal
>
Hi. Thanks for your patience. I now have the FSF copyright assignment.
> On 5/15/24 13:27, Seyed Sajad Kahani wrote:
> > This patch resolves PR114915 by replacing the logic that fills in
> > the
> > missing levels in do_auto_deduction in cp/pt.cc.
>
> I miss the text in your original patch that explained the problem
> more.
>
The patch that I will send in the upcoming email contains the
explanation from the v1 patch as well.
> > The new approach now trims targs if the depth of targs is deeper
> > than desired
> > (this will only happen in specific contexts), and still fills targs
> > with empty
> > layers if it has fewer depths than expected.
> >
> > PR c++/114915
>
> This line needs to start with a tab.
>
> > gcc/cp/ChangeLog:
> >
> > * pt.cc (do_auto_deduction): Handle excess outer template
> > arguments during constrained auto satisfaction.
>
> This one, too. These issues are flagged by git gcc-verify, and are
> easier to avoid with git gcc-commit-mklog.
>
Thanks for guiding me. The commit is now verified.
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/cpp2a/concepts-placeholder14.C: New test.
> > * g++.dg/cpp2a/concepts-placeholder15.C: New test.
>
> This test still needs a variable template partial specialization.
>
Regarding this, I have added a simple variable template parameter
specialization to the test, but due to PR c++/115030, which I will be
working on right after this patch, a more complex test will fail.
> A few coding style nits below.
>
> > * g++.dg/cpp2a/concepts-placeholder16.C: New test.
> > ---
> > gcc/cp/pt.cc | 20 ++++++++---
> > .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
> > .../g++.dg/cpp2a/concepts-placeholder15.C | 15 +++++++++
> > .../g++.dg/cpp2a/concepts-placeholder16.C | 33
> > +++++++++++++++++++
> > 4 files changed, 83 insertions(+), 4 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-
> > placeholder14.C
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-
> > placeholder15.C
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-
> > placeholder16.C
> >
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 32640f8e9..ecfda67aa 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init,
> > tree auto_node,
> > full_targs = add_outermost_template_args (tmpl,
> > full_targs);
> > full_targs = add_to_template_args (full_targs, targs);
> >
> > + int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> > + int have = TMPL_ARGS_DEPTH (full_targs);
> > +
> > + if (want < have)
> > + {
> > + // if a constrained auto is declared in an explicit
> > specialization
>
> We generally use C-style /* */ comments, that start with a capital
> letter and end with a period.
>
> > + gcc_assert (context == adc_variable_type || context ==
> > adc_return_type
> > + || context == adc_decomp_type);
>
> The || should line up with the 'c' on the previous line.
>
> > + tree trimmed_full_args = get_innermost_template_args
> > + (full_targs, want);
>
> We try to avoid having arguments to the left of the function name;
> here
> I'd start the new line with the = instead.
>
> > + full_targs = trimmed_full_args;
> > + }
> > +
>
> Unnecessary tab on this line.
>
> > /* HACK: Compensate for callers not always communicating
> > all levels of
> > outer template arguments by filling in the outermost
> > missing levels
> > with dummy levels before checking satisfaction. We'll
> > still crash
> > @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init,
> > tree auto_node,
> > these missing levels, but this hack otherwise allows us
> > to handle a
> > large subset of possible constraints (including all non-
> > dependent
> > constraints). */
> > - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL
> > (auto_node)
> > - - TMPL_ARGS_DEPTH (full_targs)))
> > + if (want > have)
> > {
> > - tree dummy_levels = make_tree_vec (missing_levels);
> > - for (int i = 0; i < missing_levels; ++i)
> > + tree dummy_levels = make_tree_vec (want - have);
> > + for (int i = 0; i < want - have; ++i)
> > TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> > full_targs = add_to_template_args (dummy_levels,
> > full_targs);
> > }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > new file mode 100644
> > index 000000000..fcdbd7608
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> > @@ -0,0 +1,19 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<typename T>
> > +concept C = __is_same(T, int);
> > +
> > +template<typename T>
> > +void f() {
> > +}
> > +
> > +template<>
> > +void f<int>() {
> > + C auto x = 1;
> > +}
> > +
> > +int main() {
> > + f<int>();
> > + return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > new file mode 100644
> > index 000000000..b4f73f407
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> > @@ -0,0 +1,15 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<typename T, typename U>
> > +concept C = __is_same(T, U);
> > +
> > +template<typename T>
> > +int x = 0;
> > +
> > +template<>
> > +C<double> auto x<double> = 1.0;
> > +
> > +int main() {
> > + return 0;
> > +}
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > new file mode 100644
> > index 000000000..f808ef1b6
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> > @@ -0,0 +1,33 @@
> > +// PR c++/114915
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<typename T, typename U>
> > +concept C = __is_same(T, U);
> > +
> > +template<typename T>
> > +struct A
> > +{
> > + template<typename U>
> > + void f() {
> > + }
> > +};
> > +
> > +template<>
> > +template<>
> > +void A<int>::f<int>() {
> > + C<int> auto x = 1;
> > +}
> > +
> > +template<>
> > +template<typename U>
> > +void A<bool>::f() {
> > + C<int> auto x = 1;
> > +}
> > +
> > +int main() {
> > + A<bool> a;
> > + a.f<char>();
> > + A<int> b;
> > + b.f<int>();
> > + return 0;
> > +}
>
Thank you so much for your comments. They are all fixed now.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v5] c++: fix constained auto deduction in templ spec scopes [PR114915]
2024-05-22 20:30 ` Jason Merrill
2024-06-14 14:15 ` sska1377
@ 2024-06-14 14:18 ` Seyed Sajad Kahani
2024-07-03 17:53 ` Patrick Palka
1 sibling, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-06-14 14:18 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason, Seyed Sajad Kahani
When deducing auto for `adc_return_type`, `adc_variable_type`, and
`adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
template arguments to be used for satisfaction. This is done by one of the
following, depending on the scope:
1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
conditions) for non-function scope variable declaration deductions
(decl.cc:8527).
Then, we do not retrieve the deeper layers of the template arguments; instead,
we fill the missing levels with dummy levels (pt.cc:31260).
The problem (that is shown in PR114915) is that we do not consider the case
where the deduction happens in a template specialization scope. In this case,
the type is not dependent on the outermost template arguments (which are
the specialization arguments). Yet, we still resolve the outermost template
arguments, and then the number of layers in the template arguments exceeds the
number of levels in the type. This causes the missing levels to be negative.
This leads to the rejection of valid code and ICEs (like segfault) in the
release mode. In the debug mode, it is possible to show as an assertion failure
(when creating a tree_vec with a negative size).
This patch resolves PR114915 by replacing the logic that fills in the
missing levels in do_auto_deduction in cp/pt.cc.
The new approach now trims targs if the depth of targs is deeper than desired
(this will only happen in specific contexts), and still fills targs with empty
layers if it has fewer depths than expected.
PR c++/114915
gcc/cp/ChangeLog:
* pt.cc (do_auto_deduction): Handle excess outer template
arguments during constrained auto satisfaction.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.
---
gcc/cp/pt.cc | 20 ++++++++---
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 26 +++++++++++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
4 files changed, 94 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e9..2206d9ffe 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
full_targs = add_outermost_template_args (tmpl, full_targs);
full_targs = add_to_template_args (full_targs, targs);
+ int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
+ int have = TMPL_ARGS_DEPTH (full_targs);
+
+ if (want < have)
+ {
+ /* If a constrained auto is declared in an explicit specialization. */
+ gcc_assert (context == adc_variable_type || context == adc_return_type
+ || context == adc_decomp_type);
+ tree trimmed_full_args
+ = get_innermost_template_args (full_targs, want);
+ full_targs = trimmed_full_args;
+ }
+
/* HACK: Compensate for callers not always communicating all levels of
outer template arguments by filling in the outermost missing levels
with dummy levels before checking satisfaction. We'll still crash
@@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- - TMPL_ARGS_DEPTH (full_targs)))
+ if (want > have)
{
- tree dummy_levels = make_tree_vec (missing_levels);
- for (int i = 0; i < missing_levels; ++i)
+ tree dummy_levels = make_tree_vec (want - have);
+ for (int i = 0; i < want - have; ++i)
TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
full_targs = add_to_template_args (dummy_levels, full_targs);
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b507e4165
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,26 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+template <typename T>
+struct S {};
+
+template<typename T>
+int y = 0;
+
+template<typename T>
+C<char> auto y<S<T>> = 'c';
+
+int main() {
+ if (y<S<int>> != 'c')
+ return 1;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
--
2.45.2
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v5] c++: fix constained auto deduction in templ spec scopes [PR114915]
2024-06-14 14:18 ` [PATCH v5] " Seyed Sajad Kahani
@ 2024-07-03 17:53 ` Patrick Palka
2024-07-18 16:03 ` [PATCH v6] c++: Fix constrained " Seyed Sajad Kahani
0 siblings, 1 reply; 25+ messages in thread
From: Patrick Palka @ 2024-07-03 17:53 UTC (permalink / raw)
To: Seyed Sajad Kahani; +Cc: gcc-patches, ppalka, jason
On Fri, 14 Jun 2024, Seyed Sajad Kahani wrote:
> When deducing auto for `adc_return_type`, `adc_variable_type`, and
> `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
> template arguments to be used for satisfaction. This is done by one of the
> following, depending on the scope:
>
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
> extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
> conditions) for non-function scope variable declaration deductions
> (decl.cc:8527).
>
> Then, we do not retrieve the deeper layers of the template arguments; instead,
> we fill the missing levels with dummy levels (pt.cc:31260).
>
> The problem (that is shown in PR114915) is that we do not consider the case
> where the deduction happens in a template specialization scope. In this case,
> the type is not dependent on the outermost template arguments (which are
> the specialization arguments). Yet, we still resolve the outermost template
> arguments, and then the number of layers in the template arguments exceeds the
> number of levels in the type. This causes the missing levels to be negative.
> This leads to the rejection of valid code and ICEs (like segfault) in the
> release mode. In the debug mode, it is possible to show as an assertion failure
> (when creating a tree_vec with a negative size).
>
> This patch resolves PR114915 by replacing the logic that fills in the
> missing levels in do_auto_deduction in cp/pt.cc.
> The new approach now trims targs if the depth of targs is deeper than desired
> (this will only happen in specific contexts), and still fills targs with empty
> layers if it has fewer depths than expected.
LGTM
>
> PR c++/114915
>
> gcc/cp/ChangeLog:
>
> * pt.cc (do_auto_deduction): Handle excess outer template
> arguments during constrained auto satisfaction.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/concepts-placeholder14.C: New test.
> * g++.dg/cpp2a/concepts-placeholder15.C: New test.
> * g++.dg/cpp2a/concepts-placeholder16.C: New test.
> ---
> gcc/cp/pt.cc | 20 ++++++++---
> .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
> .../g++.dg/cpp2a/concepts-placeholder15.C | 26 +++++++++++++++
> .../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
> 4 files changed, 94 insertions(+), 4 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 32640f8e9..2206d9ffe 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> full_targs = add_outermost_template_args (tmpl, full_targs);
> full_targs = add_to_template_args (full_targs, targs);
>
> + int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
> + int have = TMPL_ARGS_DEPTH (full_targs);
> +
> + if (want < have)
> + {
> + /* If a constrained auto is declared in an explicit specialization. */
> + gcc_assert (context == adc_variable_type || context == adc_return_type
> + || context == adc_decomp_type);
> + tree trimmed_full_args
> + = get_innermost_template_args (full_targs, want);
> + full_targs = trimmed_full_args;
> + }
> +
> /* HACK: Compensate for callers not always communicating all levels of
> outer template arguments by filling in the outermost missing levels
> with dummy levels before checking satisfaction. We'll still crash
> @@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> these missing levels, but this hack otherwise allows us to handle a
> large subset of possible constraints (including all non-dependent
> constraints). */
> - if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
> - - TMPL_ARGS_DEPTH (full_targs)))
> + if (want > have)
> {
> - tree dummy_levels = make_tree_vec (missing_levels);
> - for (int i = 0; i < missing_levels; ++i)
> + tree dummy_levels = make_tree_vec (want - have);
> + for (int i = 0; i < want - have; ++i)
> TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
> full_targs = add_to_template_args (dummy_levels, full_targs);
> }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 000000000..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T>
> +concept C = __is_same(T, int);
> +
> +template<typename T>
> +void f() {
> +}
> +
> +template<>
> +void f<int>() {
> + C auto x = 1;
> +}
> +
> +int main() {
> + f<int>();
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 000000000..b507e4165
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,26 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +int x = 0;
> +
> +template<>
> +C<double> auto x<double> = 1.0;
> +
> +template <typename T>
> +struct S {};
> +
> +template<typename T>
> +int y = 0;
> +
> +template<typename T>
> +C<char> auto y<S<T>> = 'c';
> +
> +int main() {
> + if (y<S<int>> != 'c')
> + return 1;
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 000000000..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +struct A
> +{
> + template<typename U>
> + void f() {
> + }
> +};
> +
> +template<>
> +template<>
> +void A<int>::f<int>() {
> + C<int> auto x = 1;
> +}
> +
> +template<>
> +template<typename U>
> +void A<bool>::f() {
> + C<int> auto x = 1;
> +}
> +
> +int main() {
> + A<bool> a;
> + a.f<char>();
> + A<int> b;
> + b.f<int>();
> + return 0;
> +}
> --
> 2.45.2
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v6] c++: Fix constrained auto deduction in templ spec scopes [PR114915]
2024-07-03 17:53 ` Patrick Palka
@ 2024-07-18 16:03 ` Seyed Sajad Kahani
2024-07-19 2:16 ` Jason Merrill
0 siblings, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-07-18 16:03 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason, Seyed Sajad Kahani
When deducing auto for `adc_return_type`, `adc_variable_type`, and
`adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
template arguments to be used for satisfaction. This is done by one of the
following, depending on the scope:
1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
conditions) for non-function scope variable declaration deductions
(decl.cc:8527).
Then, we do not retrieve the deeper layers of the template arguments; instead,
we fill the missing levels with dummy levels (pt.cc:31260).
The problem (that is shown in PR114915) is that we do not consider the case
where the deduction happens in a template specialization scope. In this case,
the type is not dependent on the outermost template arguments (which are
the specialization arguments). Yet, we still resolve the outermost template
arguments, and then the number of layers in the template arguments exceeds the
number of levels in the type. This causes the missing levels to be negative.
This leads to the rejection of valid code and ICEs (like segfault) in the
release mode. In the debug mode, it is possible to show as an assertion failure
(when creating a tree_vec with a negative size).
This patch resolves PR114915 by replacing the logic that fills in the
missing levels in do_auto_deduction in cp/pt.cc.
The new approach now trims targs if the depth of targs is deeper than desired
(this will only happen in specific contexts), and still fills targs with empty
layers if it has fewer depths than expected.
PR c++/114915
gcc/cp/ChangeLog:
* pt.cc (do_auto_deduction): Handle excess outer template
arguments during constrained auto satisfaction.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.
---
gcc/cp/pt.cc | 20 ++++++++---
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++++++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 26 +++++++++++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++++++++++++
4 files changed, 94 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e9..484dd5952 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31253,6 +31253,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
full_targs = add_outermost_template_args (tmpl, full_targs);
full_targs = add_to_template_args (full_targs, targs);
+ int want = TEMPLATE_TYPE_ORIG_LEVEL (auto_node);
+ int have = TMPL_ARGS_DEPTH (full_targs);
+
+ if (want < have)
+ {
+ /* If a constrained auto is declared in an explicit specialization. */
+ gcc_assert (context == adc_variable_type || context == adc_return_type
+ || context == adc_decomp_type);
+ tree trimmed_full_args
+ = get_innermost_template_args (full_targs, want);
+ full_targs = trimmed_full_args;
+ }
+
/* HACK: Compensate for callers not always communicating all levels of
outer template arguments by filling in the outermost missing levels
with dummy levels before checking satisfaction. We'll still crash
@@ -31260,11 +31273,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
these missing levels, but this hack otherwise allows us to handle a
large subset of possible constraints (including all non-dependent
constraints). */
- if (int missing_levels = (TEMPLATE_TYPE_ORIG_LEVEL (auto_node)
- - TMPL_ARGS_DEPTH (full_targs)))
+ if (want > have)
{
- tree dummy_levels = make_tree_vec (missing_levels);
- for (int i = 0; i < missing_levels; ++i)
+ tree dummy_levels = make_tree_vec (want - have);
+ for (int i = 0; i < want - have; ++i)
TREE_VEC_ELT (dummy_levels, i) = make_tree_vec (0);
full_targs = add_to_template_args (dummy_levels, full_targs);
}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b507e4165
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,26 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+template <typename T>
+struct S {};
+
+template<typename T>
+int y = 0;
+
+template<typename T>
+C<char> auto y<S<T>> = 'c';
+
+int main() {
+ if (y<S<int>> != 'c')
+ return 1;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
--
2.45.2
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6] c++: Fix constrained auto deduction in templ spec scopes [PR114915]
2024-07-18 16:03 ` [PATCH v6] c++: Fix constrained " Seyed Sajad Kahani
@ 2024-07-19 2:16 ` Jason Merrill
2024-08-11 18:11 ` Seyed Sajad Kahani
0 siblings, 1 reply; 25+ messages in thread
From: Jason Merrill @ 2024-07-19 2:16 UTC (permalink / raw)
To: Seyed Sajad Kahani, gcc-patches; +Cc: ppalka
On 7/18/24 12:03 PM, Seyed Sajad Kahani wrote:
> When deducing auto for `adc_return_type`, `adc_variable_type`, and
> `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
> template arguments to be used for satisfaction. This is done by one of the
> following, depending on the scope:
>
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
> extracting DECL_TI_ARGS from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
> conditions) for non-function scope variable declaration deductions
> (decl.cc:8527).
>
> Then, we do not retrieve the deeper layers of the template arguments; instead,
> we fill the missing levels with dummy levels (pt.cc:31260).
>
> The problem (that is shown in PR114915) is that we do not consider the case
> where the deduction happens in a template specialization scope. In this case,
> the type is not dependent on the outermost template arguments (which are
> the specialization arguments). Yet, we still resolve the outermost template
> arguments, and then the number of layers in the template arguments exceeds the
> number of levels in the type. This causes the missing levels to be negative.
> This leads to the rejection of valid code and ICEs (like segfault) in the
> release mode. In the debug mode, it is possible to show as an assertion failure
> (when creating a tree_vec with a negative size).
>
> This patch resolves PR114915 by replacing the logic that fills in the
> missing levels in do_auto_deduction in cp/pt.cc.
> The new approach now trims targs if the depth of targs is deeper than desired
> (this will only happen in specific contexts), and still fills targs with empty
> layers if it has fewer depths than expected.
I would prefer to set outer_targs correctly in the first place, where
it's currently set a few lines above. And to factor that out so other
callers can use it as well instead of DECL_TI_ARGS.
It seems like we want something close to outer_template_args, but it
doesn't currently handle function scope decls or full specializations.
Jason
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6] c++: Fix constrained auto deduction in templ spec scopes [PR114915]
2024-07-19 2:16 ` Jason Merrill
@ 2024-08-11 18:11 ` Seyed Sajad Kahani
2024-08-11 19:41 ` [PATCH] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030] Seyed Sajad Kahani
0 siblings, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-08-11 18:11 UTC (permalink / raw)
To: Jason Merrill, gcc-patches; +Cc: ppalka
Hi.
Based on your comments here, and the discussions in another thread
https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657703.html
I have made another patch to resolve this issue (as well as another
bug) that I will be sending right now.
On Thu, 2024-07-18 at 22:16 -0400, Jason Merrill wrote:
> On 7/18/24 12:03 PM, Seyed Sajad Kahani wrote:
> > When deducing auto for `adc_return_type`, `adc_variable_type`, and
> > `adc_decomp_type` contexts (at the usage time), we try to resolve
> > the outermost
> > template arguments to be used for satisfaction. This is done by one
> > of the
> > following, depending on the scope:
> >
> > 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope
> > and
> > extracting DECL_TI_ARGS from it for function scope deductions
> > (pt.cc:31236).
> > 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside
> > with other
> > conditions) for non-function scope variable declaration deductions
> > (decl.cc:8527).
> >
> > Then, we do not retrieve the deeper layers of the template
> > arguments; instead,
> > we fill the missing levels with dummy levels (pt.cc:31260).
> >
> > The problem (that is shown in PR114915) is that we do not consider
> > the case
> > where the deduction happens in a template specialization scope. In
> > this case,
> > the type is not dependent on the outermost template arguments
> > (which are
> > the specialization arguments). Yet, we still resolve the outermost
> > template
> > arguments, and then the number of layers in the template arguments
> > exceeds the
> > number of levels in the type. This causes the missing levels to be
> > negative.
> > This leads to the rejection of valid code and ICEs (like segfault)
> > in the
> > release mode. In the debug mode, it is possible to show as an
> > assertion failure
> > (when creating a tree_vec with a negative size).
> >
> > This patch resolves PR114915 by replacing the logic that fills in
> > the
> > missing levels in do_auto_deduction in cp/pt.cc.
> > The new approach now trims targs if the depth of targs is deeper
> > than desired
> > (this will only happen in specific contexts), and still fills targs
> > with empty
> > layers if it has fewer depths than expected.
>
> I would prefer to set outer_targs correctly in the first place, where
> it's currently set a few lines above. And to factor that out so
> other
> callers can use it as well instead of DECL_TI_ARGS.
>
> It seems like we want something close to outer_template_args, but it
> doesn't currently handle function scope decls or full
> specializations.
>
> Jason
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030]
2024-08-11 18:11 ` Seyed Sajad Kahani
@ 2024-08-11 19:41 ` Seyed Sajad Kahani
2024-08-12 15:04 ` [PATCH v2] " Seyed Sajad Kahani
0 siblings, 1 reply; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-08-11 19:41 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason, Seyed Sajad Kahani
When deducing auto for `adc_return_type`, `adc_variable_type`, and
`adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
template arguments to be used for satisfaction. This is done by one of the
following, depending on the scope:
1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
extracting `DECL_TI_ARGS` from it for function scope deductions (pt.cc:31236).
2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
conditions) for non-function scope variable declaration deductions
(decl.cc:8527).
Note that `DECL_TI_ARGS` for partial and explicit specializations will yield the
arguments with respect to the most_general_template, which is the primary
template. This can lead to rejection of valid code or acceptance of invalid code
(PR115030) in a partial specialization context. For an explicitly specialized
case, due to the mismatch between the desired depth and the actual depth of
args, it can lead to ICEs (PR114915) where we intend to fill the missing levels
with dummy levels (pt.cc:31260), while the missing levels are negative.
This patch resolves PR114915 and PR115030 by replacing the logic of extracting
args for the declaration in those two places with `outer_template_args`.
`outer_template_args` is an existing function that was used in limited contexts to
do so. Now, it is extended to handle partial and explicit specializations and
lambda functions as well. A few inevitable changes are also made to the
signature of some functions, relaxing `const_tree` to `tree`.
PR c++/114915
PR c++/115030
gcc/cp/ChangeLog:
* constraint.cc (maybe_substitute_reqs_for): Relax the argument type to
be compatible with outer_template_args.
* cp-tree.h (outer_template_args): Relax the argument type and add an
optional argument.
(maybe_substitute_reqs_for): Relax the argument type to be compatible
with outer_template_args.
* decl.cc (cp_finish_decl): Replace the logic of extracting args with
outer_template_args.
* pt.cc (outer_template_args): Handle partial and explicit
specializations and lambda functions.
(do_auto_deduction): Replace the logic of extracting args with
outer_template_args.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.
* g++.dg/cpp2a/concepts-placeholder17.C: New test.
---
gcc/cp/constraint.cc | 2 +-
gcc/cp/cp-tree.h | 4 +-
gcc/cp/decl.cc | 4 +-
gcc/cp/pt.cc | 71 ++++++++++++-------
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 26 +++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 +++++++++
.../g++.dg/cpp2a/concepts-placeholder17.C | 21 ++++++
8 files changed, 150 insertions(+), 30 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index ebf4255e5..a1c3962c4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1332,7 +1332,7 @@ remove_constraints (tree t)
for declaration matching. */
tree
-maybe_substitute_reqs_for (tree reqs, const_tree decl)
+maybe_substitute_reqs_for (tree reqs, tree decl)
{
if (reqs == NULL_TREE)
return NULL_TREE;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9a8c86591..2d6733f57 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7215,7 +7215,7 @@ extern tree maybe_set_retval_sentinel (void);
extern tree template_parms_to_args (tree);
extern tree template_parms_level_to_args (tree);
extern tree generic_targs_for (tree);
-extern tree outer_template_args (const_tree);
+extern tree outer_template_args (tree, bool = true);
/* in expr.cc */
extern tree cplus_expand_constant (tree);
@@ -8560,7 +8560,7 @@ extern void remove_constraints (tree);
extern tree current_template_constraints (void);
extern tree associate_classtype_constraints (tree);
extern tree build_constraints (tree, tree);
-extern tree maybe_substitute_reqs_for (tree, const_tree);
+extern tree maybe_substitute_reqs_for (tree, tree);
extern tree get_trailing_function_requirements (tree);
extern tree get_shorthand_constraints (tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a139b293e..6b68d5f39 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8557,10 +8557,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
&& DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_INFO (decl)
&& !DECL_FUNCTION_SCOPE_P (decl))
- /* The outer template arguments might be needed for satisfaction.
+ /* The outer template arguments might be needed for satisfaction.
(For function scope variables, do_auto_deduction will obtain the
outer template arguments from current_function_decl.) */
- outer_targs = DECL_TI_ARGS (decl);
+ tree outer_targs = outer_template_args (decl, false);
type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
tf_warning_or_error, adc,
outer_targs, flags);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e9..e9bad58f3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4998,23 +4998,57 @@ generic_targs_for (tree tmpl)
/* Return the template arguments corresponding to the template parameters of
DECL's enclosing scope. When DECL is a member of a partial specialization,
this returns the arguments for the partial specialization as opposed to those
- for the primary template, which is the main difference between this function
- and simply using e.g. the TYPE_TI_ARGS of DECL's DECL_CONTEXT. */
-
+ for the primary template, and for a full specialization, it returns null.
+ STRIP_CURRENT specifies whether it should include currently declared
+ templates or not. */
tree
-outer_template_args (const_tree decl)
+outer_template_args (tree decl, bool strip_current /* = true */)
{
if (TREE_CODE (decl) == TEMPLATE_DECL)
decl = DECL_TEMPLATE_RESULT (decl);
tree ti = get_template_info (decl);
+ tree args = NULL_TREE;
+
if (!ti)
- return NULL_TREE;
- tree args = TI_ARGS (ti);
- if (!PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
- return args;
- if (TMPL_ARGS_DEPTH (args) == 1)
- return NULL_TREE;
- return strip_innermost_template_args (args, 1);
+ {
+ if (DECL_FUNCTION_SCOPE_P (decl))
+ args = outer_template_args (DECL_CONTEXT (decl), false);
+ }
+ else
+ {
+ if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)) && TI_PARTIAL_INFO (ti))
+ ti = TI_PARTIAL_INFO (ti);
+
+ /* For an explicitly specialized declaration. */
+ if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_SPECIALIZATION (decl))
+ args = NULL_TREE;
+ else
+ {
+ args = TI_ARGS (ti);
+
+ int parms_depth =
+ TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (TI_TEMPLATE (ti)));
+ /* If any of outer scopes are explicitly specialized. */
+ if (TMPL_ARGS_DEPTH(args) > parms_depth)
+ args = get_innermost_template_args (args, parms_depth);
+
+ if (strip_current && PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
+ {
+ if (TMPL_ARGS_DEPTH (args) == 1)
+ return NULL_TREE;
+ return strip_innermost_template_args (args, 1);
+ }
+ }
+ }
+
+ /* Special treatment of lambda functions. */
+ if (LAMBDA_FUNCTION_P (decl) && !strip_current)
+ {
+ tree regen_targs = lambda_regenerating_args (decl);
+ args = add_to_template_args (regen_targs, args);
+ }
+
+ return args;
}
/* Update the declared TYPE by doing any lookups which were thought to be
@@ -31233,20 +31267,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
|| context == adc_variable_type
|| context == adc_decomp_type)
if (tree fn = current_function_decl)
- if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
- {
- outer_targs = DECL_TEMPLATE_INFO (fn)
- ? DECL_TI_ARGS (fn) : NULL_TREE;
- if (LAMBDA_FUNCTION_P (fn))
- {
- /* As in satisfy_declaration_constraints. */
- tree regen_args = lambda_regenerating_args (fn);
- if (outer_targs)
- outer_targs = add_to_template_args (regen_args, outer_targs);
- else
- outer_targs = regen_args;
- }
- }
+ outer_targs = outer_template_args(fn, false);
tree full_targs = outer_targs;
if (context == adc_unify && tmpl)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b507e4165
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,26 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+template <typename T>
+struct S {};
+
+template<typename T>
+int y = 0;
+
+template<typename T>
+C<char> auto y<S<T>> = 'c';
+
+int main() {
+ if (y<S<int>> != 'c')
+ return 1;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
new file mode 100644
index 000000000..4a8dcb3d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
@@ -0,0 +1,21 @@
+
+// PR c++/115030
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template <typename T>
+struct s {
+};
+
+template <typename T>
+char v = 'a';
+
+template<typename T>
+C<T> auto v<s<T>> = 'c';
+
+int main() {
+ v<s<char>> = 'b';
+ return 0;
+}
\ No newline at end of file
--
2.46.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v2] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030]
2024-08-11 19:41 ` [PATCH] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030] Seyed Sajad Kahani
@ 2024-08-12 15:04 ` Seyed Sajad Kahani
2024-09-04 21:27 ` PING " Seyed Sajad Kahani
2024-09-12 17:32 ` Patrick Palka
0 siblings, 2 replies; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-08-12 15:04 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason, Seyed Sajad Kahani
When deducing auto for `adc_return_type`, `adc_variable_type`, and
`adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
template arguments to be used for satisfaction. This is done by one of the
following, depending on the scope:
1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
extracting `DECL_TI_ARGS` from it for function scope deductions (pt.cc:31236).
2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
conditions) for non-function scope variable declaration deductions
(decl.cc:8527).
Note that `DECL_TI_ARGS` for partial and explicit specializations will yield the
arguments with respect to the most_general_template, which is the primary
template. This can lead to rejection of valid code or acceptance of invalid code
(PR115030) in a partial specialization context. For an explicitly specialized
case, due to the mismatch between the desired depth and the actual depth of
args, it can lead to ICEs (PR114915) where we intend to fill the missing levels
with dummy levels (pt.cc:31260), while the missing levels are negative.
This patch resolves PR114915 and PR115030 by replacing the logic of extracting
args for the declaration in those two places with `outer_template_args`.
`outer_template_args` is an existing function that was used in limited contexts to
do so. Now, it is extended to handle partial and explicit specializations and
lambda functions as well. A few inevitable changes are also made to the
signature of some functions, relaxing `const_tree` to `tree`.
PR c++/114915
PR c++/115030
gcc/cp/ChangeLog:
* constraint.cc (maybe_substitute_reqs_for): Relax the argument type to
be compatible with outer_template_args.
* cp-tree.h (outer_template_args): Relax the argument type and add an
optional argument.
(maybe_substitute_reqs_for): Relax the argument type to be compatible
with outer_template_args.
* decl.cc (cp_finish_decl): Replace the logic of extracting args with
outer_template_args.
* pt.cc (outer_template_args): Handle partial and explicit
specializations and lambda functions.
(do_auto_deduction): Replace the logic of extracting args with
outer_template_args.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-placeholder14.C: New test.
* g++.dg/cpp2a/concepts-placeholder15.C: New test.
* g++.dg/cpp2a/concepts-placeholder16.C: New test.
* g++.dg/cpp2a/concepts-placeholder17.C: New test.
---
gcc/cp/constraint.cc | 2 +-
gcc/cp/cp-tree.h | 4 +-
gcc/cp/decl.cc | 2 +-
gcc/cp/pt.cc | 84 +++++++++++++------
.../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++
.../g++.dg/cpp2a/concepts-placeholder15.C | 26 ++++++
.../g++.dg/cpp2a/concepts-placeholder16.C | 33 ++++++++
.../g++.dg/cpp2a/concepts-placeholder17.C | 20 +++++
8 files changed, 161 insertions(+), 29 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index ebf4255e5..a1c3962c4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1332,7 +1332,7 @@ remove_constraints (tree t)
for declaration matching. */
tree
-maybe_substitute_reqs_for (tree reqs, const_tree decl)
+maybe_substitute_reqs_for (tree reqs, tree decl)
{
if (reqs == NULL_TREE)
return NULL_TREE;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9a8c86591..2d6733f57 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7215,7 +7215,7 @@ extern tree maybe_set_retval_sentinel (void);
extern tree template_parms_to_args (tree);
extern tree template_parms_level_to_args (tree);
extern tree generic_targs_for (tree);
-extern tree outer_template_args (const_tree);
+extern tree outer_template_args (tree, bool = true);
/* in expr.cc */
extern tree cplus_expand_constant (tree);
@@ -8560,7 +8560,7 @@ extern void remove_constraints (tree);
extern tree current_template_constraints (void);
extern tree associate_classtype_constraints (tree);
extern tree build_constraints (tree, tree);
-extern tree maybe_substitute_reqs_for (tree, const_tree);
+extern tree maybe_substitute_reqs_for (tree, tree);
extern tree get_trailing_function_requirements (tree);
extern tree get_shorthand_constraints (tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a139b293e..3a9344a32 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8560,7 +8560,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
/* The outer template arguments might be needed for satisfaction.
(For function scope variables, do_auto_deduction will obtain the
outer template arguments from current_function_decl.) */
- outer_targs = DECL_TI_ARGS (decl);
+ outer_targs = outer_template_args (decl, false);
type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
tf_warning_or_error, adc,
outer_targs, flags);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32640f8e9..b446884c8 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4998,23 +4998,70 @@ generic_targs_for (tree tmpl)
/* Return the template arguments corresponding to the template parameters of
DECL's enclosing scope. When DECL is a member of a partial specialization,
this returns the arguments for the partial specialization as opposed to those
- for the primary template, which is the main difference between this function
- and simply using e.g. the TYPE_TI_ARGS of DECL's DECL_CONTEXT. */
-
+ for the primary template, and for a full specialization, it returns null.
+ STRIP_CURRENT specifies whether it should include currently declared
+ templates or not. */
tree
-outer_template_args (const_tree decl)
+outer_template_args (tree decl, bool strip_current /* = true */)
{
if (TREE_CODE (decl) == TEMPLATE_DECL)
decl = DECL_TEMPLATE_RESULT (decl);
tree ti = get_template_info (decl);
+ tree args = NULL_TREE;
+
if (!ti)
- return NULL_TREE;
- tree args = TI_ARGS (ti);
- if (!PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
- return args;
- if (TMPL_ARGS_DEPTH (args) == 1)
- return NULL_TREE;
- return strip_innermost_template_args (args, 1);
+ {
+ if (DECL_FUNCTION_SCOPE_P (decl))
+ args = outer_template_args (DECL_CONTEXT (decl), false);
+ }
+ else
+ {
+ if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)) && TI_PARTIAL_INFO (ti))
+ ti = TI_PARTIAL_INFO (ti);
+
+ /* For an explicitly specialized declaration. */
+ if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_SPECIALIZATION (decl))
+ args = NULL_TREE;
+ else
+ {
+ args = TI_ARGS (ti);
+
+ int actual_depth = TMPL_ARGS_DEPTH (args);
+ /* Finding explicitly specialized scopes */
+ for (tree tmpl = TI_TEMPLATE(ti);
+ DECL_LANG_SPECIFIC (tmpl) && DECL_TEMPLATE_INFO (tmpl);
+ tmpl = DECL_TI_TEMPLATE (tmpl))
+ {
+ if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ {
+ actual_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
+ break;
+ }
+ if (TREE_CODE (DECL_TI_TEMPLATE (tmpl)) != TEMPLATE_DECL)
+ break;
+ }
+
+ /* If any of outer scopes are explicitly specialized. */
+ if (TMPL_ARGS_DEPTH(args) > actual_depth)
+ args = get_innermost_template_args (args, actual_depth);
+
+ if (strip_current && PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
+ {
+ if (TMPL_ARGS_DEPTH (args) == 1)
+ return NULL_TREE;
+ return strip_innermost_template_args (args, 1);
+ }
+ }
+ }
+
+ /* Special treatment of lambda functions. */
+ if (LAMBDA_FUNCTION_P (decl) && !strip_current)
+ {
+ tree regen_targs = lambda_regenerating_args (decl);
+ args = add_to_template_args (regen_targs, args);
+ }
+
+ return args;
}
/* Update the declared TYPE by doing any lookups which were thought to be
@@ -31233,20 +31280,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
|| context == adc_variable_type
|| context == adc_decomp_type)
if (tree fn = current_function_decl)
- if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
- {
- outer_targs = DECL_TEMPLATE_INFO (fn)
- ? DECL_TI_ARGS (fn) : NULL_TREE;
- if (LAMBDA_FUNCTION_P (fn))
- {
- /* As in satisfy_declaration_constraints. */
- tree regen_args = lambda_regenerating_args (fn);
- if (outer_targs)
- outer_targs = add_to_template_args (regen_args, outer_targs);
- else
- outer_targs = regen_args;
- }
- }
+ outer_targs = outer_template_args(fn, false);
tree full_targs = outer_targs;
if (context == adc_unify && tmpl)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
new file mode 100644
index 000000000..fcdbd7608
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
@@ -0,0 +1,19 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+concept C = __is_same(T, int);
+
+template<typename T>
+void f() {
+}
+
+template<>
+void f<int>() {
+ C auto x = 1;
+}
+
+int main() {
+ f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
new file mode 100644
index 000000000..b507e4165
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
@@ -0,0 +1,26 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+int x = 0;
+
+template<>
+C<double> auto x<double> = 1.0;
+
+template <typename T>
+struct S {};
+
+template<typename T>
+int y = 0;
+
+template<typename T>
+C<char> auto y<S<T>> = 'c';
+
+int main() {
+ if (y<S<int>> != 'c')
+ return 1;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
new file mode 100644
index 000000000..f808ef1b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
@@ -0,0 +1,33 @@
+// PR c++/114915
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template<typename T>
+struct A
+{
+ template<typename U>
+ void f() {
+ }
+};
+
+template<>
+template<>
+void A<int>::f<int>() {
+ C<int> auto x = 1;
+}
+
+template<>
+template<typename U>
+void A<bool>::f() {
+ C<int> auto x = 1;
+}
+
+int main() {
+ A<bool> a;
+ a.f<char>();
+ A<int> b;
+ b.f<int>();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
new file mode 100644
index 000000000..a8bd48e39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
@@ -0,0 +1,20 @@
+// PR c++/115030
+// { dg-do compile { target c++20 } }
+
+template<typename T, typename U>
+concept C = __is_same(T, U);
+
+template <typename T>
+struct s {
+};
+
+template <typename T>
+char v = 'a';
+
+template<typename T>
+C<T> auto v<s<T>> = 'c';
+
+int main() {
+ v<s<char>> = 'b';
+ return 0;
+}
--
2.46.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* PING [PATCH v2] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030]
2024-08-12 15:04 ` [PATCH v2] " Seyed Sajad Kahani
@ 2024-09-04 21:27 ` Seyed Sajad Kahani
2024-09-12 17:32 ` Patrick Palka
1 sibling, 0 replies; 25+ messages in thread
From: Seyed Sajad Kahani @ 2024-09-04 21:27 UTC (permalink / raw)
To: gcc-patches; +Cc: ppalka, jason
I'm gently pinging about the patch I submitted:
https://gcc.gnu.org/pipermail/gcc-patches/2024-August/660177.html
This patch was created in response to Jason's comments here:
https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657739.html
I appreciate your time and consideration.
Thank you.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030]
2024-08-12 15:04 ` [PATCH v2] " Seyed Sajad Kahani
2024-09-04 21:27 ` PING " Seyed Sajad Kahani
@ 2024-09-12 17:32 ` Patrick Palka
2024-09-15 12:58 ` Jason Merrill
1 sibling, 1 reply; 25+ messages in thread
From: Patrick Palka @ 2024-09-12 17:32 UTC (permalink / raw)
To: Seyed Sajad Kahani; +Cc: gcc-patches, ppalka, jason
On Mon, 12 Aug 2024, Seyed Sajad Kahani wrote:
> When deducing auto for `adc_return_type`, `adc_variable_type`, and
> `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
> template arguments to be used for satisfaction. This is done by one of the
> following, depending on the scope:
>
> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
> extracting `DECL_TI_ARGS` from it for function scope deductions (pt.cc:31236).
> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
> conditions) for non-function scope variable declaration deductions
> (decl.cc:8527).
>
> Note that `DECL_TI_ARGS` for partial and explicit specializations will yield the
> arguments with respect to the most_general_template, which is the primary
> template. This can lead to rejection of valid code or acceptance of invalid code
> (PR115030) in a partial specialization context. For an explicitly specialized
> case, due to the mismatch between the desired depth and the actual depth of
> args, it can lead to ICEs (PR114915) where we intend to fill the missing levels
> with dummy levels (pt.cc:31260), while the missing levels are negative.
>
> This patch resolves PR114915 and PR115030 by replacing the logic of extracting
> args for the declaration in those two places with `outer_template_args`.
> `outer_template_args` is an existing function that was used in limited contexts to
> do so. Now, it is extended to handle partial and explicit specializations and
> lambda functions as well. A few inevitable changes are also made to the
> signature of some functions, relaxing `const_tree` to `tree`.
Thanks for working on this and for the patch ping!
>
> PR c++/114915
> PR c++/115030
>
> gcc/cp/ChangeLog:
>
> * constraint.cc (maybe_substitute_reqs_for): Relax the argument type to
> be compatible with outer_template_args.
> * cp-tree.h (outer_template_args): Relax the argument type and add an
> optional argument.
> (maybe_substitute_reqs_for): Relax the argument type to be compatible
> with outer_template_args.
> * decl.cc (cp_finish_decl): Replace the logic of extracting args with
> outer_template_args.
> * pt.cc (outer_template_args): Handle partial and explicit
> specializations and lambda functions.
Jason, I'm not sure if you had in mind extending outer_template_args
with a flag like you have, or creating a new function?
> (do_auto_deduction): Replace the logic of extracting args with
> outer_template_args.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/concepts-placeholder14.C: New test.
> * g++.dg/cpp2a/concepts-placeholder15.C: New test.
> * g++.dg/cpp2a/concepts-placeholder16.C: New test.
> * g++.dg/cpp2a/concepts-placeholder17.C: New test.
> ---
> gcc/cp/constraint.cc | 2 +-
> gcc/cp/cp-tree.h | 4 +-
> gcc/cp/decl.cc | 2 +-
> gcc/cp/pt.cc | 84 +++++++++++++------
> .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++
> .../g++.dg/cpp2a/concepts-placeholder15.C | 26 ++++++
> .../g++.dg/cpp2a/concepts-placeholder16.C | 33 ++++++++
> .../g++.dg/cpp2a/concepts-placeholder17.C | 20 +++++
> 8 files changed, 161 insertions(+), 29 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
>
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index ebf4255e5..a1c3962c4 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -1332,7 +1332,7 @@ remove_constraints (tree t)
> for declaration matching. */
>
> tree
> -maybe_substitute_reqs_for (tree reqs, const_tree decl)
> +maybe_substitute_reqs_for (tree reqs, tree decl)
> {
> if (reqs == NULL_TREE)
> return NULL_TREE;
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 9a8c86591..2d6733f57 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7215,7 +7215,7 @@ extern tree maybe_set_retval_sentinel (void);
> extern tree template_parms_to_args (tree);
> extern tree template_parms_level_to_args (tree);
> extern tree generic_targs_for (tree);
> -extern tree outer_template_args (const_tree);
> +extern tree outer_template_args (tree, bool = true);
>
> /* in expr.cc */
> extern tree cplus_expand_constant (tree);
> @@ -8560,7 +8560,7 @@ extern void remove_constraints (tree);
> extern tree current_template_constraints (void);
> extern tree associate_classtype_constraints (tree);
> extern tree build_constraints (tree, tree);
> -extern tree maybe_substitute_reqs_for (tree, const_tree);
> +extern tree maybe_substitute_reqs_for (tree, tree);
> extern tree get_trailing_function_requirements (tree);
> extern tree get_shorthand_constraints (tree);
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index a139b293e..3a9344a32 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -8560,7 +8560,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
> /* The outer template arguments might be needed for satisfaction.
> (For function scope variables, do_auto_deduction will obtain the
> outer template arguments from current_function_decl.) */
> - outer_targs = DECL_TI_ARGS (decl);
> + outer_targs = outer_template_args (decl, false);
> type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
> tf_warning_or_error, adc,
> outer_targs, flags);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 32640f8e9..b446884c8 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -4998,23 +4998,70 @@ generic_targs_for (tree tmpl)
> /* Return the template arguments corresponding to the template parameters of
> DECL's enclosing scope. When DECL is a member of a partial specialization,
> this returns the arguments for the partial specialization as opposed to those
> - for the primary template, which is the main difference between this function
> - and simply using e.g. the TYPE_TI_ARGS of DECL's DECL_CONTEXT. */
> -
> + for the primary template, and for a full specialization, it returns null.
> + STRIP_CURRENT specifies whether it should include currently declared
> + templates or not. */
> tree
> -outer_template_args (const_tree decl)
> +outer_template_args (tree decl, bool strip_current /* = true */)
> {
> if (TREE_CODE (decl) == TEMPLATE_DECL)
> decl = DECL_TEMPLATE_RESULT (decl);
> tree ti = get_template_info (decl);
> + tree args = NULL_TREE;
> +
> if (!ti)
> - return NULL_TREE;
> - tree args = TI_ARGS (ti);
> - if (!PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
> - return args;
> - if (TMPL_ARGS_DEPTH (args) == 1)
> - return NULL_TREE;
> - return strip_innermost_template_args (args, 1);
> + {
> + if (DECL_FUNCTION_SCOPE_P (decl))
> + args = outer_template_args (DECL_CONTEXT (decl), false);
> + }
> + else
> + {
> + if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)) && TI_PARTIAL_INFO (ti))
> + ti = TI_PARTIAL_INFO (ti);
More of a style issue, but I think this if could be moved into ...
> +
> + /* For an explicitly specialized declaration. */
> + if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_SPECIALIZATION (decl))
> + args = NULL_TREE;
> + else
> + {
... this branch which is the only user? And then we can flatten this
nested if into an else if chain.
I'll defer to Jason review of the logic since he has more of a vision of
what it should look like.
> + args = TI_ARGS (ti);
> +
> + int actual_depth = TMPL_ARGS_DEPTH (args);
> + /* Finding explicitly specialized scopes */
> + for (tree tmpl = TI_TEMPLATE(ti);
> + DECL_LANG_SPECIFIC (tmpl) && DECL_TEMPLATE_INFO (tmpl);
> + tmpl = DECL_TI_TEMPLATE (tmpl))
> + {
> + if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
> + {
> + actual_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
> + break;
> + }
> + if (TREE_CODE (DECL_TI_TEMPLATE (tmpl)) != TEMPLATE_DECL)
> + break;
> + }
> +
> + /* If any of outer scopes are explicitly specialized. */
> + if (TMPL_ARGS_DEPTH(args) > actual_depth)
> + args = get_innermost_template_args (args, actual_depth);
> +
> + if (strip_current && PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
> + {
> + if (TMPL_ARGS_DEPTH (args) == 1)
> + return NULL_TREE;
> + return strip_innermost_template_args (args, 1);
> + }
> + }
> + }
> +
> + /* Special treatment of lambda functions. */
> + if (LAMBDA_FUNCTION_P (decl) && !strip_current)
> + {
> + tree regen_targs = lambda_regenerating_args (decl);
> + args = add_to_template_args (regen_targs, args);
> + }
> +
> + return args;
> }
>
> /* Update the declared TYPE by doing any lookups which were thought to be
> @@ -31233,20 +31280,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
> || context == adc_variable_type
> || context == adc_decomp_type)
> if (tree fn = current_function_decl)
> - if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
> - {
> - outer_targs = DECL_TEMPLATE_INFO (fn)
> - ? DECL_TI_ARGS (fn) : NULL_TREE;
> - if (LAMBDA_FUNCTION_P (fn))
> - {
> - /* As in satisfy_declaration_constraints. */
> - tree regen_args = lambda_regenerating_args (fn);
> - if (outer_targs)
> - outer_targs = add_to_template_args (regen_args, outer_targs);
> - else
> - outer_targs = regen_args;
> - }
> - }
> + outer_targs = outer_template_args(fn, false);
>
> tree full_targs = outer_targs;
> if (context == adc_unify && tmpl)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> new file mode 100644
> index 000000000..fcdbd7608
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
> @@ -0,0 +1,19 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T>
> +concept C = __is_same(T, int);
> +
> +template<typename T>
> +void f() {
> +}
> +
> +template<>
> +void f<int>() {
> + C auto x = 1;
> +}
> +
> +int main() {
> + f<int>();
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> new file mode 100644
> index 000000000..b507e4165
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
> @@ -0,0 +1,26 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +int x = 0;
> +
> +template<>
> +C<double> auto x<double> = 1.0;
> +
> +template <typename T>
> +struct S {};
> +
> +template<typename T>
> +int y = 0;
> +
> +template<typename T>
> +C<char> auto y<S<T>> = 'c';
> +
> +int main() {
> + if (y<S<int>> != 'c')
> + return 1;
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> new file mode 100644
> index 000000000..f808ef1b6
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
> @@ -0,0 +1,33 @@
> +// PR c++/114915
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template<typename T>
> +struct A
> +{
> + template<typename U>
> + void f() {
> + }
> +};
> +
> +template<>
> +template<>
> +void A<int>::f<int>() {
> + C<int> auto x = 1;
> +}
> +
> +template<>
> +template<typename U>
> +void A<bool>::f() {
> + C<int> auto x = 1;
> +}
> +
> +int main() {
> + A<bool> a;
> + a.f<char>();
> + A<int> b;
> + b.f<int>();
> + return 0;
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
> new file mode 100644
> index 000000000..a8bd48e39
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
> @@ -0,0 +1,20 @@
> +// PR c++/115030
> +// { dg-do compile { target c++20 } }
> +
> +template<typename T, typename U>
> +concept C = __is_same(T, U);
> +
> +template <typename T>
> +struct s {
> +};
> +
> +template <typename T>
> +char v = 'a';
> +
> +template<typename T>
> +C<T> auto v<s<T>> = 'c';
> +
> +int main() {
> + v<s<char>> = 'b';
> + return 0;
> +}
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v2] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030]
2024-09-12 17:32 ` Patrick Palka
@ 2024-09-15 12:58 ` Jason Merrill
0 siblings, 0 replies; 25+ messages in thread
From: Jason Merrill @ 2024-09-15 12:58 UTC (permalink / raw)
To: Patrick Palka, Seyed Sajad Kahani; +Cc: gcc-patches
On 9/12/24 1:32 PM, Patrick Palka wrote:
> On Mon, 12 Aug 2024, Seyed Sajad Kahani wrote:
>
>> When deducing auto for `adc_return_type`, `adc_variable_type`, and
>> `adc_decomp_type` contexts (at the usage time), we try to resolve the outermost
>> template arguments to be used for satisfaction. This is done by one of the
>> following, depending on the scope:
>>
>> 1. Checking the `DECL_TEMPLATE_INFO` of the current function scope and
>> extracting `DECL_TI_ARGS` from it for function scope deductions (pt.cc:31236).
>> 2. Checking the `DECL_TEMPLATE_INFO` of the declaration (alongside with other
>> conditions) for non-function scope variable declaration deductions
>> (decl.cc:8527).
>>
>> Note that `DECL_TI_ARGS` for partial and explicit specializations will yield the
>> arguments with respect to the most_general_template, which is the primary
>> template. This can lead to rejection of valid code or acceptance of invalid code
>> (PR115030) in a partial specialization context. For an explicitly specialized
>> case, due to the mismatch between the desired depth and the actual depth of
>> args, it can lead to ICEs (PR114915) where we intend to fill the missing levels
>> with dummy levels (pt.cc:31260), while the missing levels are negative.
>>
>> This patch resolves PR114915 and PR115030 by replacing the logic of extracting
>> args for the declaration in those two places with `outer_template_args`.
>> `outer_template_args` is an existing function that was used in limited contexts to
>> do so. Now, it is extended to handle partial and explicit specializations and
>> lambda functions as well. A few inevitable changes are also made to the
>> signature of some functions, relaxing `const_tree` to `tree`.
>
> Thanks for working on this and for the patch ping!
Yes, absolutely!
>> PR c++/114915
>> PR c++/115030
>>
>> gcc/cp/ChangeLog:
>>
>> * constraint.cc (maybe_substitute_reqs_for): Relax the argument type to
>> be compatible with outer_template_args.
>> * cp-tree.h (outer_template_args): Relax the argument type and add an
>> optional argument.
>> (maybe_substitute_reqs_for): Relax the argument type to be compatible
>> with outer_template_args.
>> * decl.cc (cp_finish_decl): Replace the logic of extracting args with
>> outer_template_args.
>> * pt.cc (outer_template_args): Handle partial and explicit
>> specializations and lambda functions.
>
> Jason, I'm not sure if you had in mind extending outer_template_args
> with a flag like you have, or creating a new function?
Indeed, I'd prefer for the two uses to use different names rather than
add a flag. Maybe targs_for_substitution, with outer_template_args
becoming a wrapper that just calls strip_innermost_template_args.
>> (do_auto_deduction): Replace the logic of extracting args with
>> outer_template_args.
>>
>> gcc/testsuite/ChangeLog:
>>
>> * g++.dg/cpp2a/concepts-placeholder14.C: New test.
>> * g++.dg/cpp2a/concepts-placeholder15.C: New test.
>> * g++.dg/cpp2a/concepts-placeholder16.C: New test.
>> * g++.dg/cpp2a/concepts-placeholder17.C: New test.
>> ---
>> gcc/cp/constraint.cc | 2 +-
>> gcc/cp/cp-tree.h | 4 +-
>> gcc/cp/decl.cc | 2 +-
>> gcc/cp/pt.cc | 84 +++++++++++++------
>> .../g++.dg/cpp2a/concepts-placeholder14.C | 19 +++++
>> .../g++.dg/cpp2a/concepts-placeholder15.C | 26 ++++++
>> .../g++.dg/cpp2a/concepts-placeholder16.C | 33 ++++++++
>> .../g++.dg/cpp2a/concepts-placeholder17.C | 20 +++++
>> 8 files changed, 161 insertions(+), 29 deletions(-)
>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
>>
>> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
>> index ebf4255e5..a1c3962c4 100644
>> --- a/gcc/cp/constraint.cc
>> +++ b/gcc/cp/constraint.cc
>> @@ -1332,7 +1332,7 @@ remove_constraints (tree t)
>> for declaration matching. */
>>
>> tree
>> -maybe_substitute_reqs_for (tree reqs, const_tree decl)
>> +maybe_substitute_reqs_for (tree reqs, tree decl)
>> {
>> if (reqs == NULL_TREE)
>> return NULL_TREE;
>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>> index 9a8c86591..2d6733f57 100644
>> --- a/gcc/cp/cp-tree.h
>> +++ b/gcc/cp/cp-tree.h
>> @@ -7215,7 +7215,7 @@ extern tree maybe_set_retval_sentinel (void);
>> extern tree template_parms_to_args (tree);
>> extern tree template_parms_level_to_args (tree);
>> extern tree generic_targs_for (tree);
>> -extern tree outer_template_args (const_tree);
>> +extern tree outer_template_args (tree, bool = true);
>>
>> /* in expr.cc */
>> extern tree cplus_expand_constant (tree);
>> @@ -8560,7 +8560,7 @@ extern void remove_constraints (tree);
>> extern tree current_template_constraints (void);
>> extern tree associate_classtype_constraints (tree);
>> extern tree build_constraints (tree, tree);
>> -extern tree maybe_substitute_reqs_for (tree, const_tree);
>> +extern tree maybe_substitute_reqs_for (tree, tree);
>> extern tree get_trailing_function_requirements (tree);
>> extern tree get_shorthand_constraints (tree);
>>
>> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
>> index a139b293e..3a9344a32 100644
>> --- a/gcc/cp/decl.cc
>> +++ b/gcc/cp/decl.cc
>> @@ -8560,7 +8560,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
>> /* The outer template arguments might be needed for satisfaction.
>> (For function scope variables, do_auto_deduction will obtain the
>> outer template arguments from current_function_decl.) */
>> - outer_targs = DECL_TI_ARGS (decl);
>> + outer_targs = outer_template_args (decl, false);
>> type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, auto_node,
>> tf_warning_or_error, adc,
>> outer_targs, flags);
>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>> index 32640f8e9..b446884c8 100644
>> --- a/gcc/cp/pt.cc
>> +++ b/gcc/cp/pt.cc
>> @@ -4998,23 +4998,70 @@ generic_targs_for (tree tmpl)
>> /* Return the template arguments corresponding to the template parameters of
>> DECL's enclosing scope. When DECL is a member of a partial specialization,
>> this returns the arguments for the partial specialization as opposed to those
>> - for the primary template, which is the main difference between this function
>> - and simply using e.g. the TYPE_TI_ARGS of DECL's DECL_CONTEXT. */
>> -
>> + for the primary template, and for a full specialization, it returns null.
>> + STRIP_CURRENT specifies whether it should include currently declared
>> + templates or not. */
>> tree
>> -outer_template_args (const_tree decl)
>> +outer_template_args (tree decl, bool strip_current /* = true */)
>> {
>> if (TREE_CODE (decl) == TEMPLATE_DECL)
>> decl = DECL_TEMPLATE_RESULT (decl);
>> tree ti = get_template_info (decl);
>> + tree args = NULL_TREE;
>> +
>> if (!ti)
>> - return NULL_TREE;
>> - tree args = TI_ARGS (ti);
>> - if (!PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
>> - return args;
>> - if (TMPL_ARGS_DEPTH (args) == 1)
>> - return NULL_TREE;
>> - return strip_innermost_template_args (args, 1);
>> + {
>> + if (DECL_FUNCTION_SCOPE_P (decl))
>> + args = outer_template_args (DECL_CONTEXT (decl), false);
>> + }
>> + else
>> + {
>> + if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)) && TI_PARTIAL_INFO (ti))
>> + ti = TI_PARTIAL_INFO (ti);
>
> More of a style issue, but I think this if could be moved into ...
>
>> +
>> + /* For an explicitly specialized declaration. */
>> + if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_SPECIALIZATION (decl))
>> + args = NULL_TREE;
>> + else
>> + {
>
> ... this branch which is the only user? And then we can flatten this
> nested if into an else if chain.
>
> I'll defer to Jason review of the logic since he has more of a vision of
> what it should look like.
>
>> + args = TI_ARGS (ti);
>> +
>> + int actual_depth = TMPL_ARGS_DEPTH (args);
>> + /* Finding explicitly specialized scopes */
Missing . at end of comment.
>> + for (tree tmpl = TI_TEMPLATE(ti);
Missing space before (
>> + DECL_LANG_SPECIFIC (tmpl) && DECL_TEMPLATE_INFO (tmpl);
>> + tmpl = DECL_TI_TEMPLATE (tmpl))
>> + {
>> + if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
>> + {
>> + actual_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
>> + break;
>> + }
>> + if (TREE_CODE (DECL_TI_TEMPLATE (tmpl)) != TEMPLATE_DECL)
>> + break;
>> + }
Can you use template_for_substitution or most_general_template instead
of writing another version of that loop?
>> + /* If any of outer scopes are explicitly specialized. */
Need two spaces after .
>> + if (TMPL_ARGS_DEPTH(args) > actual_depth)
Missing space.
>> + args = get_innermost_template_args (args, actual_depth);
>> +
>> + if (strip_current && PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
>> + {
>> + if (TMPL_ARGS_DEPTH (args) == 1)
>> + return NULL_TREE;
>> + return strip_innermost_template_args (args, 1);
>> + }
>> + }
>> + }
>> +
>> + /* Special treatment of lambda functions. */
>> + if (LAMBDA_FUNCTION_P (decl) && !strip_current)
Perhaps the !strip_current check should be a checking_assert rather than
a condition?
>> + {
>> + tree regen_targs = lambda_regenerating_args (decl);
>> + args = add_to_template_args (regen_targs, args);
>> + }
>> +
>> + return args;
>> }
>>
>> /* Update the declared TYPE by doing any lookups which were thought to be
>> @@ -31233,20 +31280,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
>> || context == adc_variable_type
>> || context == adc_decomp_type)
>> if (tree fn = current_function_decl)
>> - if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
>> - {
>> - outer_targs = DECL_TEMPLATE_INFO (fn)
>> - ? DECL_TI_ARGS (fn) : NULL_TREE;
>> - if (LAMBDA_FUNCTION_P (fn))
>> - {
>> - /* As in satisfy_declaration_constraints. */
>> - tree regen_args = lambda_regenerating_args (fn);
>> - if (outer_targs)
>> - outer_targs = add_to_template_args (regen_args, outer_targs);
>> - else
>> - outer_targs = regen_args;
>> - }
>> - }
>> + outer_targs = outer_template_args(fn, false);
>>
>> tree full_targs = outer_targs;
>> if (context == adc_unify && tmpl)
>> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>> new file mode 100644
>> index 000000000..fcdbd7608
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder14.C
>> @@ -0,0 +1,19 @@
>> +// PR c++/114915
>> +// { dg-do compile { target c++20 } }
>> +
>> +template<typename T>
>> +concept C = __is_same(T, int);
>> +
>> +template<typename T>
>> +void f() {
>> +}
>> +
>> +template<>
>> +void f<int>() {
>> + C auto x = 1;
>> +}
>> +
>> +int main() {
>> + f<int>();
>> + return 0;
>> +}
>> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>> new file mode 100644
>> index 000000000..b507e4165
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder15.C
>> @@ -0,0 +1,26 @@
>> +// PR c++/114915
>> +// { dg-do compile { target c++20 } }
>> +
>> +template<typename T, typename U>
>> +concept C = __is_same(T, U);
>> +
>> +template<typename T>
>> +int x = 0;
>> +
>> +template<>
>> +C<double> auto x<double> = 1.0;
>> +
>> +template <typename T>
>> +struct S {};
>> +
>> +template<typename T>
>> +int y = 0;
>> +
>> +template<typename T>
>> +C<char> auto y<S<T>> = 'c';
>> +
>> +int main() {
>> + if (y<S<int>> != 'c')
>> + return 1;
>> + return 0;
>> +}
>> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>> new file mode 100644
>> index 000000000..f808ef1b6
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder16.C
>> @@ -0,0 +1,33 @@
>> +// PR c++/114915
>> +// { dg-do compile { target c++20 } }
>> +
>> +template<typename T, typename U>
>> +concept C = __is_same(T, U);
>> +
>> +template<typename T>
>> +struct A
>> +{
>> + template<typename U>
>> + void f() {
>> + }
>> +};
>> +
>> +template<>
>> +template<>
>> +void A<int>::f<int>() {
>> + C<int> auto x = 1;
>> +}
>> +
>> +template<>
>> +template<typename U>
>> +void A<bool>::f() {
>> + C<int> auto x = 1;
>> +}
>> +
>> +int main() {
>> + A<bool> a;
>> + a.f<char>();
>> + A<int> b;
>> + b.f<int>();
>> + return 0;
>> +}
>> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
>> new file mode 100644
>> index 000000000..a8bd48e39
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder17.C
>> @@ -0,0 +1,20 @@
>> +// PR c++/115030
>> +// { dg-do compile { target c++20 } }
>> +
>> +template<typename T, typename U>
>> +concept C = __is_same(T, U);
>> +
>> +template <typename T>
>> +struct s {
>> +};
>> +
>> +template <typename T>
>> +char v = 'a';
>> +
>> +template<typename T>
>> +C<T> auto v<s<T>> = 'c';
>> +
>> +int main() {
>> + v<s<char>> = 'b';
>> + return 0;
>> +}
>> --
>> 2.46.0
>>
>>
>
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2024-09-15 12:58 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-01 22:52 [PATCH] Fix auto deduction for template specialization scopes [114915] Seyed Sajad Kahani
2024-05-03 16:24 ` Patrick Palka
2024-05-04 14:11 ` Seyed Sajad Kahani
2024-05-04 15:15 ` [PATCH v2] Fix auto deduction for template specialization scopes [PR114915] Seyed Sajad Kahani
2024-05-06 18:46 ` Patrick Palka
2024-05-10 12:43 ` Seyed Sajad Kahani
2024-05-10 12:47 ` [PATCH v3] " Seyed Sajad Kahani
2024-05-15 15:07 ` [PATCH v3] c++: " Patrick Palka
2024-05-15 15:09 ` Patrick Palka
2024-05-15 17:27 ` [PATCH v4] c++: fix constained auto deduction in templ spec " Seyed Sajad Kahani
2024-05-22 20:30 ` Jason Merrill
2024-06-14 14:15 ` sska1377
2024-06-14 14:18 ` [PATCH v5] " Seyed Sajad Kahani
2024-07-03 17:53 ` Patrick Palka
2024-07-18 16:03 ` [PATCH v6] c++: Fix constrained " Seyed Sajad Kahani
2024-07-19 2:16 ` Jason Merrill
2024-08-11 18:11 ` Seyed Sajad Kahani
2024-08-11 19:41 ` [PATCH] c++: Fix constrained auto deduction templ parms resolution [PR114915, PR115030] Seyed Sajad Kahani
2024-08-12 15:04 ` [PATCH v2] " Seyed Sajad Kahani
2024-09-04 21:27 ` PING " Seyed Sajad Kahani
2024-09-12 17:32 ` Patrick Palka
2024-09-15 12:58 ` Jason Merrill
2024-05-22 15:41 ` [PATCH] Fix auto deduction for template specialization scopes [114915] Jason Merrill
2024-05-22 16:48 ` Patrick Palka
2024-05-22 17:32 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).