@@ -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;
@@ -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);
@@ -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);
@@ -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)
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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