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
