diff mbox series

[1/2] c++: Improve access checking inside templates [PR41437]

Message ID 20200605211608.2661402-1-ppalka@redhat.com
State New
Headers show
Series [1/2] c++: Improve access checking inside templates [PR41437] | expand

Commit Message

Patrick Palka June 5, 2020, 9:16 p.m. UTC
This patch generalizes our existing functionality for deferring access
checking of typedefs when parsing a function or class template to now
defer all kinds of access checks until template instantiation time,
including member function and member object accesses.

Since all access checks eventually go through enforce_access, the main
component of this patch is new handling inside enforce_access to defer
the current access check if we're inside a template.  The bulk of the
rest of the patch consists of removing now-unneeded code pertaining to
suppressing access checks inside templates or pertaining to
typedef-specific access handling.  Renamings and other changes with no
functional impact have been split off into the followup patch.

Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
building parts of boost, cmcstl2 and other libraries.

gcc/cp/ChangeLog:

	PR c++/41437
	PR c++/47346
	* call.c (enforce_access): Move to semantics.c.
	* cp-tree.h (enforce_access): Delete.
	(get_types_needing_access_check): Delete.
	(add_typedef_to_current_template_for_access_check): Delete.
	* decl.c (make_typename_type): Adjust accordingly.  Use
	check_accessibility_of_qualified_id instead of directly using
	perform_or_defer_access_check.
	* parser.c (cp_parser_template_declaration_after_parameters):
	Don't push a dk_no_check access state when parsing a template.
	* pt.c (get_types_needing_access_check): Delete.
	(append_type_to_template_for_access_check_1): Delete.
	(perform_typedefs_access_check): Adjust.  If type_decl is a
	FIELD_DECL, also check its DECL_CONTEXT for dependence. Use
	tsubst_copy instead of tsubst to substitute into type_decl so
	that we substitute into the DECL_CONTEXT of a FIELD_DECL.
	(append_type_to_template_for_access_check): Delete.
	* search.c (accessible_p): Remove the processing_template_decl
	early exit.
	* semantics.c (enforce_access): Moved from call.c.  If we're
	parsing a template and the access check failed, add the check to
	TI_TYPEDEFS_NEEDING_ACCESS_CHECKING.
	(perform_or_defer_access_check): Adjust comment.
	(add_typedef_to_current_template_for_access_check): Delete.
	(check_accessibility_of_qualified_id):  Adjust accordingly.
	Guard use of DECL_NONSTATIC_MEMBER_P so that we don't use it on
	a USING_DECL with empty TREE_TYPE.  If the scope of the accessed
	decl is not dependent but the qualifying scope, then still
	proceed with the access check so that we defer it.

gcc/testsuite/ChangeLog:

	PR c++/41437
	PR c++/47346
	* g++.dg/cpp2a/concepts-using2.C: Adjust.
	* g++.dg/lto/20081219_1.C: Adjust.
	* g++.dg/lto/20091002-1_0.C: Adjust.
	* g++.dg/lto/pr65475c_0.C: Adjust.
	* g++.dg/opt/dump1.C: Adjust.
	* g++.dg/other/pr53574.C: Adjust.
	* g++.dg/template/access30.C: New test.
	* g++.dg/template/access31.C: New test.
	* g++.dg/wrappers/wrapper-around-type-pack-expansion.C: Adjust.

libstdc++-v3/ChangeLog:

	PR libstdc++/94003
	* testsuite/20_util/is_constructible/94003.cc: New test.
---
 gcc/cp/call.c                                 |  36 ------
 gcc/cp/cp-tree.h                              |   6 -
 gcc/cp/decl.c                                 |   8 +-
 gcc/cp/parser.c                               |   4 -
 gcc/cp/pt.c                                   | 120 +-----------------
 gcc/cp/search.c                               |  15 ---
 gcc/cp/semantics.c                            | 112 +++++++++-------
 gcc/testsuite/g++.dg/cpp2a/concepts-using2.C  |   4 +-
 gcc/testsuite/g++.dg/lto/20081219_1.C         |   2 +-
 gcc/testsuite/g++.dg/lto/20091002-1_0.C       |   2 +-
 gcc/testsuite/g++.dg/lto/pr65475c_0.C         |   3 +
 gcc/testsuite/g++.dg/opt/dump1.C              |   2 +-
 gcc/testsuite/g++.dg/other/pr53574.C          |   2 +-
 gcc/testsuite/g++.dg/template/access30.C      |  10 ++
 gcc/testsuite/g++.dg/template/access31.C      |  29 +++++
 .../wrapper-around-type-pack-expansion.C      |   2 +-
 .../20_util/is_constructible/94003.cc         |  28 ++++
 17 files changed, 150 insertions(+), 235 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/access30.C
 create mode 100644 gcc/testsuite/g++.dg/template/access31.C
 create mode 100644 libstdc++-v3/testsuite/20_util/is_constructible/94003.cc

Comments

Jason Merrill June 11, 2020, 10:12 p.m. UTC | #1
On 6/5/20 5:16 PM, Patrick Palka wrote:
> This patch generalizes our existing functionality for deferring access
> checking of typedefs when parsing a function or class template to now
> defer all kinds of access checks until template instantiation time,
> including member function and member object accesses.
> 
> Since all access checks eventually go through enforce_access, the main
> component of this patch is new handling inside enforce_access to defer
> the current access check if we're inside a template.  The bulk of the
> rest of the patch consists of removing now-unneeded code pertaining to
> suppressing access checks inside templates or pertaining to
> typedef-specific access handling.  Renamings and other changes with no
> functional impact have been split off into the followup patch.

Great!

> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
> building parts of boost, cmcstl2 and other libraries.

> -      && !dependent_type_p (qualifying_type))
> +      && !dependent_type_p (scope))

This needs a comment.  And it occurs to me that if we're only going to 
check access if scope is non-dependent, we can check that much earlier 
and avoid the need to guard DECL_NONSTATIC_MEMBER_P.

Jason
Patrick Palka June 15, 2020, 1:56 p.m. UTC | #2
On Thu, 11 Jun 2020, Jason Merrill wrote:

> On 6/5/20 5:16 PM, Patrick Palka wrote:
> > This patch generalizes our existing functionality for deferring access
> > checking of typedefs when parsing a function or class template to now
> > defer all kinds of access checks until template instantiation time,
> > including member function and member object accesses.
> > 
> > Since all access checks eventually go through enforce_access, the main
> > component of this patch is new handling inside enforce_access to defer
> > the current access check if we're inside a template.  The bulk of the
> > rest of the patch consists of removing now-unneeded code pertaining to
> > suppressing access checks inside templates or pertaining to
> > typedef-specific access handling.  Renamings and other changes with no
> > functional impact have been split off into the followup patch.
> 
> Great!
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
> > building parts of boost, cmcstl2 and other libraries.
> 
> > -      && !dependent_type_p (qualifying_type))
> > +      && !dependent_type_p (scope))
> 
> This needs a comment.  And it occurs to me that if we're only going to check
> access if scope is non-dependent, we can check that much earlier and avoid the
> need to guard DECL_NONSTATIC_MEMBER_P.

Good point, that works much better.  Done in the below patch, which has
been bootstrapped and regtested  on x86_64-pc-linux-gnu and has been
smoke tested on a number of libraries.  (The followup patch remains
essentially unchanged.)

-- >8 --

Subject: [PATCH 1/2] c++: Improve access checking inside templates [PR41437]

This patch generalizes our existing functionality for deferring access
checking of typedefs when parsing a function or class template to now
defer all kinds of access checks until template instantiation time,
including member function and member object accesses.

Since all access checks eventually go through enforce_access, the main
component of this patch is new handling inside enforce_access to defer
the current access check if we're inside a template.  The bulk of the
rest of the patch consists of removing now-unneeded code pertaining to
suppressing access checks inside templates or pertaining to
typedef-specific access handling.  Renamings and other changes with no
functional impact have been split off into the followup patch.

Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
building parts of boost, cmcstl2 and other libraries.

gcc/cp/ChangeLog:

	PR c++/41437
	PR c++/47346
	* call.c (enforce_access): Move to semantics.c.
	* cp-tree.h (enforce_access): Delete.
	(get_types_needing_access_check): Delete.
	(add_typedef_to_current_template_for_access_check): Delete.
	* decl.c (make_typename_type): Adjust accordingly.  Use
	check_accessibility_of_qualified_id instead of directly using
	perform_or_defer_access_check.
	* parser.c (cp_parser_template_declaration_after_parameters):
	Don't push a dk_no_check access state when parsing a template.
	* pt.c (get_types_needing_access_check): Delete.
	(append_type_to_template_for_access_check_1): Delete.
	(perform_typedefs_access_check): Adjust.  If type_decl is a
	FIELD_DECL, also check its DECL_CONTEXT for dependence. Use
	tsubst_copy instead of tsubst to substitute into type_decl so
	that we substitute into the DECL_CONTEXT of a FIELD_DECL.
	(append_type_to_template_for_access_check): Delete.
	* search.c (accessible_p): Remove the processing_template_decl
	early exit.
	* semantics.c (enforce_access): Moved from call.c.  If we're
	parsing a template and the access check failed, add the check to
	TI_TYPEDEFS_NEEDING_ACCESS_CHECKING.
	(perform_or_defer_access_check): Adjust comment.
	(add_typedef_to_current_template_for_access_check): Delete.
	(check_accessibility_of_qualified_id):  Adjust accordingly.
	Exit early if the scope is dependent.

gcc/testsuite/ChangeLog:

	PR c++/41437
	PR c++/47346
	* g++.dg/cpp2a/concepts-using2.C: Adjust.
	* g++.dg/lto/20081219_1.C: Adjust.
	* g++.dg/lto/20091002-1_0.C: Adjust.
	* g++.dg/lto/pr65475c_0.C: Adjust.
	* g++.dg/opt/dump1.C: Adjust.
	* g++.dg/other/pr53574.C: Adjust.
	* g++.dg/template/access30.C: New test.
	* g++.dg/template/access31.C: New test.
	* g++.dg/wrappers/wrapper-around-type-pack-expansion.C: Adjust.

libstdc++-v3/ChangeLog:

	PR libstdc++/94003
	* testsuite/20_util/is_constructible/94003.cc: New test.
---
 gcc/cp/call.c                                 |  36 -----
 gcc/cp/cp-tree.h                              |   6 -
 gcc/cp/decl.c                                 |   8 +-
 gcc/cp/parser.c                               |   4 -
 gcc/cp/pt.c                                   | 120 +----------------
 gcc/cp/search.c                               |  15 ---
 gcc/cp/semantics.c                            | 127 +++++++++++-------
 gcc/testsuite/g++.dg/cpp2a/concepts-using2.C  |   4 +-
 gcc/testsuite/g++.dg/lto/20081219_1.C         |   2 +-
 gcc/testsuite/g++.dg/lto/20091002-1_0.C       |   2 +-
 gcc/testsuite/g++.dg/lto/pr65475c_0.C         |   3 +
 gcc/testsuite/g++.dg/opt/dump1.C              |   2 +-
 gcc/testsuite/g++.dg/other/pr53574.C          |   2 +-
 gcc/testsuite/g++.dg/template/access30.C      |  10 ++
 gcc/testsuite/g++.dg/template/access31.C      |  29 ++++
 .../wrapper-around-type-pack-expansion.C      |   2 +-
 .../20_util/is_constructible/94003.cc         |  28 ++++
 17 files changed, 159 insertions(+), 241 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/access30.C
 create mode 100644 gcc/testsuite/g++.dg/template/access31.C
 create mode 100644 libstdc++-v3/testsuite/20_util/is_constructible/94003.cc

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index b99959f76f9..b55dc83f0e7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7083,42 +7083,6 @@ complain_about_access (tree decl, tree diag_decl, bool issue_error)
     }
 }
 
-/* If the current scope isn't allowed to access DECL along
-   BASETYPE_PATH, give an error.  The most derived class in
-   BASETYPE_PATH is the one used to qualify DECL. DIAG_DECL is
-   the declaration to use in the error diagnostic.  */
-
-bool
-enforce_access (tree basetype_path, tree decl, tree diag_decl,
-		tsubst_flags_t complain, access_failure_info *afi)
-{
-  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
-
-  if (flag_new_inheriting_ctors
-      && DECL_INHERITED_CTOR (decl))
-    {
-      /* 7.3.3/18: The additional constructors are accessible if they would be
-	 accessible when used to construct an object of the corresponding base
-	 class.  */
-      decl = strip_inheriting_ctors (decl);
-      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
-				   ba_any, NULL, complain);
-    }
-
-  if (!accessible_p (basetype_path, decl, true))
-    {
-      if (flag_new_inheriting_ctors)
-	diag_decl = strip_inheriting_ctors (diag_decl);
-      if (complain & tf_error)
-	complain_about_access (decl, diag_decl, true);
-      if (afi)
-	afi->record_access_failure (basetype_path, decl, diag_decl);
-      return false;
-    }
-
-  return true;
-}
-
 /* Initialize a temporary of type TYPE with EXPR.  The FLAGS are a
    bitwise or of LOOKUP_* values.  If any errors are warnings are
    generated, set *DIAGNOSTIC_FN to "error" or "warning",
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 44cb10cfee5..771d51cc283 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6339,9 +6339,6 @@ class access_failure_info
 };
 
 extern void complain_about_access		(tree, tree, bool);
-extern bool enforce_access			(tree, tree, tree,
-						 tsubst_flags_t,
-						 access_failure_info *afi = NULL);
 extern void push_defarg_context			(tree);
 extern void pop_defarg_context			(void);
 extern tree convert_default_arg			(tree, tree, tree, int,
@@ -6939,7 +6936,6 @@ extern tree make_pack_expansion                 (tree, tsubst_flags_t = tf_warni
 extern bool check_for_bare_parameter_packs      (tree, location_t = UNKNOWN_LOCATION);
 extern tree build_template_info			(tree, tree);
 extern tree get_template_info			(const_tree);
-extern vec<qualified_typedef_usage_t, va_gc> *get_types_needing_access_check (tree);
 extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
@@ -7257,8 +7253,6 @@ extern void finish_mem_initializers		(tree);
 extern tree check_template_template_default_arg (tree);
 extern bool expand_or_defer_fn_1		(tree);
 extern void expand_or_defer_fn			(tree);
-extern void add_typedef_to_current_template_for_access_check (tree, tree,
-							      location_t);
 extern bool check_accessibility_of_qualified_id (tree, tree, tree, tsubst_flags_t);
 extern tree finish_qualified_id_expr		(tree, tree, bool, bool,
 						 bool, bool, tsubst_flags_t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b8bd09b37e6..539609e8ada 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4009,14 +4009,10 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
       return error_mark_node;
     }
 
-  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
+  if (!check_accessibility_of_qualified_id (t, /*object_type=*/NULL_TREE,
+					    context, complain))
     return error_mark_node;
 
-  /* If we are currently parsing a template and if T is a typedef accessed
-     through CONTEXT then we need to remember and check access of T at
-     template instantiation time.  */
-  add_typedef_to_current_template_for_access_check (t, context, input_location);
-
   if (want_template)
     return lookup_template_class (t, TREE_OPERAND (fullname, 1),
 				  NULL_TREE, context,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bc66e6e5c50..799f310bcee 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -29118,16 +29118,12 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
     decl = cp_parser_concept_definition (parser);
   else
     {
-      /* There are no access checks when parsing a template, as we do not
-	 know if a specialization will be a friend.  */
-      push_deferring_access_checks (dk_no_check);
       cp_token *token = cp_lexer_peek_token (parser->lexer);
       decl = cp_parser_single_declaration (parser,
 					   checks,
 					   member_p,
                                            /*explicit_specialization_p=*/false,
 					   &friend_p);
-      pop_deferring_access_checks ();
 
       /* If this is a member template declaration, let the front
 	 end know.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index cdf6a3eeaf3..bab48c2fdf6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -216,8 +216,6 @@ static bool dependent_type_p_r (tree);
 static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
 static tree tsubst_decl (tree, tree, tsubst_flags_t);
 static void perform_typedefs_access_check (tree tmpl, tree targs);
-static void append_type_to_template_for_access_check_1 (tree, tree, tree,
-							location_t);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
@@ -11532,7 +11530,7 @@ perform_typedefs_access_check (tree tmpl, tree targs)
     return;
 
   if (vec<qualified_typedef_usage_t, va_gc> *tdefs
-      = get_types_needing_access_check (tmpl))
+      = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (get_template_info (tmpl)))
     FOR_EACH_VEC_ELT (*tdefs, i, iter)
       {
 	tree type_decl = iter->typedef_decl;
@@ -11541,8 +11539,10 @@ perform_typedefs_access_check (tree tmpl, tree targs)
 	if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
 	  continue;
 
-	if (uses_template_parms (type_decl))
-	  type_decl = tsubst (type_decl, targs, tf_error, NULL_TREE);
+	if (uses_template_parms (type_decl)
+	    || (TREE_CODE (type_decl) == FIELD_DECL
+		&& uses_template_parms (DECL_CONTEXT (type_decl))))
+	  type_decl = tsubst_copy (type_decl, targs, tf_error, NULL_TREE);
 	if (uses_template_parms (type_scope))
 	  type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
 
@@ -29154,116 +29154,6 @@ check_auto_in_tmpl_args (tree tmpl, tree args)
   return errors;
 }
 
-/* For a given template T, return the vector of typedefs referenced
-   in T for which access check is needed at T instantiation time.
-   T is either  a FUNCTION_DECL or a RECORD_TYPE.
-   Those typedefs were added to T by the function
-   append_type_to_template_for_access_check.  */
-
-vec<qualified_typedef_usage_t, va_gc> *
-get_types_needing_access_check (tree t)
-{
-  gcc_checking_assert ((CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL));
-  
-  if (tree ti = get_template_info (t))
-    if (TI_TEMPLATE (ti))
-      return TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
-
-  return NULL;
-}
-
-/* Append the typedef TYPE_DECL used in template T to a list of typedefs
-   tied to T. That list of typedefs will be access checked at
-   T instantiation time.
-   T is either a FUNCTION_DECL or a RECORD_TYPE.
-   TYPE_DECL is a TYPE_DECL node representing a typedef.
-   SCOPE is the scope through which TYPE_DECL is accessed.
-   LOCATION is the location of the usage point of TYPE_DECL.
-
-   This function is a subroutine of
-   append_type_to_template_for_access_check.  */
-
-static void
-append_type_to_template_for_access_check_1 (tree t,
-					    tree type_decl,
-					    tree scope,
-					    location_t location)
-{
-  qualified_typedef_usage_t typedef_usage;
-  tree ti;
-
-  if (!t || t == error_mark_node)
-    return;
-
-  gcc_assert ((TREE_CODE (t) == FUNCTION_DECL
-	       || CLASS_TYPE_P (t))
-	      && type_decl
-	      && TREE_CODE (type_decl) == TYPE_DECL
-	      && scope);
-
-  if (!(ti = get_template_info (t)))
-    return;
-
-  gcc_assert (TI_TEMPLATE (ti));
-
-  typedef_usage.typedef_decl = type_decl;
-  typedef_usage.context = scope;
-  typedef_usage.locus = location;
-
-  vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), typedef_usage);
-}
-
-/* Append TYPE_DECL to the template TEMPL.
-   TEMPL is either a class type, a FUNCTION_DECL or a TEMPLATE_DECL.
-   At TEMPL instanciation time, TYPE_DECL will be checked to see
-   if it can be accessed through SCOPE.
-   LOCATION is the location of the usage point of TYPE_DECL.
-
-   e.g. consider the following code snippet:
-
-     class C
-     {
-       typedef int myint;
-     };
-
-     template<class U> struct S
-     {
-       C::myint mi; // <-- usage point of the typedef C::myint
-     };
-
-     S<char> s;
-
-   At S<char> instantiation time, we need to check the access of C::myint
-   In other words, we need to check the access of the myint typedef through
-   the C scope. For that purpose, this function will add the myint typedef
-   and the scope C through which its being accessed to a list of typedefs
-   tied to the template S. That list will be walked at template instantiation
-   time and access check performed on each typedefs it contains.
-   Note that this particular code snippet should yield an error because
-   myint is private to C.  */
-
-void
-append_type_to_template_for_access_check (tree templ,
-                                          tree type_decl,
-					  tree scope,
-					  location_t location)
-{
-  qualified_typedef_usage_t *iter;
-  unsigned i;
-
-  gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
-
-  /* Make sure we don't append the type to the template twice.  */
-  if (vec<qualified_typedef_usage_t, va_gc> *tdefs
-      = get_types_needing_access_check (templ))
-    FOR_EACH_VEC_ELT (*tdefs, i, iter)
-      if (iter->typedef_decl == type_decl && scope == iter->context)
-	return;
-
-  append_type_to_template_for_access_check_1 (templ, type_decl,
-					      scope, location);
-}
-
 /* Recursively walk over && expressions searching for EXPR. Return a reference
    to that expression.  */
 
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index b9da2fccb7f..a1a45a5ee6b 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -827,21 +827,6 @@ accessible_p (tree type, tree decl, bool consider_local_p)
   if (current_function_decl && DECL_THUNK_P (current_function_decl))
     return 1;
 
-  /* In a template declaration, we cannot be sure whether the
-     particular specialization that is instantiated will be a friend
-     or not.  Therefore, all access checks are deferred until
-     instantiation.  However, PROCESSING_TEMPLATE_DECL is set in the
-     parameter list for a template (because we may see dependent types
-     in default arguments for template parameters), and access
-     checking should be performed in the outermost parameter list.  */
-  if (processing_template_decl
-      /* FIXME CWG has been talking about doing access checking in the context
-	 of the constraint-expression, rather than the constrained declaration,
-	 in which case we would want to remove this test.  */
-      && !processing_constraint_expression_p ()
-      && (!processing_template_parmlist || processing_template_decl > 1))
-    return 1;
-
   tree otype = NULL_TREE;
   if (!TYPE_P (type))
     {
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 64587c791c6..97a37ca5d2b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -256,6 +256,68 @@ pop_to_parent_deferring_access_checks (void)
     }
 }
 
+/* If the current scope isn't allowed to access DECL along
+   BASETYPE_PATH, give an error, or if we're parsing a function or class
+   template, defer the access check to be performed at instantiation time.
+   The most derived class in BASETYPE_PATH is the one used to qualify DECL.
+   DIAG_DECL is the declaration to use in the error diagnostic.  */
+
+static bool
+enforce_access (tree basetype_path, tree decl, tree diag_decl,
+		tsubst_flags_t complain, access_failure_info *afi = NULL)
+{
+  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
+
+  if (flag_new_inheriting_ctors
+      && DECL_INHERITED_CTOR (decl))
+    {
+      /* 7.3.3/18: The additional constructors are accessible if they would be
+	 accessible when used to construct an object of the corresponding base
+	 class.  */
+      decl = strip_inheriting_ctors (decl);
+      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
+				   ba_any, NULL, complain);
+    }
+
+  tree cs = current_scope ();
+  if (processing_template_decl
+      && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
+    if (tree template_info = get_template_info (cs))
+      {
+	/* When parsing a function or class template, we in general need to
+	   defer access checks until template instantiation time, since a friend
+	   declaration may grant access only to a particular specialization of
+	   the template.  */
+
+	if (accessible_p (basetype_path, decl, /*consider_local_p=*/true))
+	  /* But if the member is deemed accessible at parse time, then we can
+	     assume it'll be accessible at instantiation time.  */
+	  return true;
+
+	/* Defer this access check until instantiation time.  */
+	qualified_typedef_usage_t typedef_usage;
+	typedef_usage.typedef_decl = decl;
+	typedef_usage.context = TREE_TYPE (basetype_path);
+	typedef_usage.locus = input_location;
+	vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (template_info),
+		       typedef_usage);
+	return true;
+      }
+
+  if (!accessible_p (basetype_path, decl, /*consider_local_p=*/true))
+    {
+      if (flag_new_inheriting_ctors)
+	diag_decl = strip_inheriting_ctors (diag_decl);
+      if (complain & tf_error)
+	complain_about_access (decl, diag_decl, true);
+      if (afi)
+	afi->record_access_failure (basetype_path, decl, diag_decl);
+      return false;
+    }
+
+  return true;
+}
+
 /* Perform the access checks in CHECKS.  The TREE_PURPOSE of each node
    is the BINFO indicating the qualifying scope used to access the
    DECL node stored in the TREE_VALUE of the node.  If CHECKS is empty
@@ -320,9 +382,7 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
   deferred_access *ptr;
   deferred_access_check *chk;
 
-
-  /* Exit if we are in a context that no access checking is performed.
-     */
+  /* Exit if we are in a context that no access checking is performed.  */
   if (deferred_access_no_check)
     return true;
 
@@ -1992,37 +2052,6 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
   return ret;
 }
 
-/* If we are currently parsing a template and we encountered a typedef
-   TYPEDEF_DECL that is being accessed though CONTEXT, this function
-   adds the typedef to a list tied to the current template.
-   At template instantiation time, that list is walked and access check
-   performed for each typedef.
-   LOCATION is the location of the usage point of TYPEDEF_DECL.  */
-
-void
-add_typedef_to_current_template_for_access_check (tree typedef_decl,
-                                                  tree context,
-						  location_t location)
-{
-    tree template_info = NULL;
-    tree cs = current_scope ();
-
-    if (!is_typedef_decl (typedef_decl)
-	|| !context
-	|| !CLASS_TYPE_P (context)
-	|| !cs)
-      return;
-
-    if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)
-      template_info = get_template_info (cs);
-
-    if (template_info
-	&& TI_TEMPLATE (template_info)
-	&& !currently_open_class (context))
-      append_type_to_template_for_access_check (cs, typedef_decl,
-						context, location);
-}
-
 /* DECL was the declaration to which a qualified-id resolved.  Issue
    an error message if it is not accessible.  If OBJECT_TYPE is
    non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
@@ -2036,28 +2065,23 @@ check_accessibility_of_qualified_id (tree decl,
 				     tree nested_name_specifier,
 				     tsubst_flags_t complain)
 {
-  tree scope;
-  tree qualifying_type = NULL_TREE;
-
-  /* If we are parsing a template declaration and if decl is a typedef,
-     add it to a list tied to the template.
-     At template instantiation time, that list will be walked and
-     access check performed.  */
-  add_typedef_to_current_template_for_access_check (decl,
-						    nested_name_specifier
-						    ? nested_name_specifier
-						    : DECL_CONTEXT (decl),
-						    input_location);
-
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
     return true;
 
   /* Determine the SCOPE of DECL.  */
-  scope = context_for_name_lookup (decl);
-  /* If the SCOPE is not a type, then DECL is not a member.  */
-  if (!TYPE_P (scope))
+  tree scope = context_for_name_lookup (decl);
+  /* If the SCOPE is not a type, then DECL is not a member.  And if the
+     SCOPE is dependent, then we'll perform this access check again after
+     substitution.  */
+  if (!TYPE_P (scope)
+      /* If SCOPE is dependent then we can't perform this access check now,
+	 and since we'll perform this access check again after substitution
+	 there's no need to explicitly defer it.  */
+      || dependent_type_p (scope))
     return true;
+
+  tree qualifying_type = NULL_TREE;
   /* Compute the scope through which DECL is being accessed.  */
   if (object_type
       /* OBJECT_TYPE might not be a class type; consider:
@@ -2096,8 +2120,7 @@ check_accessibility_of_qualified_id (tree decl,
   if (qualifying_type
       /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
 	 or similar in a default argument value.  */
-      && CLASS_TYPE_P (qualifying_type)
-      && !dependent_type_p (qualifying_type))
+      && CLASS_TYPE_P (qualifying_type))
     return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
 					  decl, complain);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
index 206b54a2883..b9a67f5d8da 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
@@ -10,7 +10,7 @@ template <typename b> using g = typename f<b>::e;
 struct b;
 template <typename b> struct f { using e = b; };
 template <typename ai> struct m { typedef g<ai> aj; };
-template <typename b> class n { typedef typename m<b>::aj e; };
+template <typename b> struct n { typedef typename m<b>::aj e; };
 template <typename b> using an = typename n<b>::e;
 template <typename> constexpr bool ao = c<true>::d;
 template <typename> constexpr bool i = c<1>::d;
@@ -38,7 +38,7 @@ template <typename da> concept de = dd<da>;
 struct {
   template <de da, typename b> void operator()(da, b);
 } di;
-class p {
+struct p {
   void begin();
 };
 template <typename> using df = p;
diff --git a/gcc/testsuite/g++.dg/lto/20081219_1.C b/gcc/testsuite/g++.dg/lto/20081219_1.C
index 1bb96ef37de..8d64a0212cb 100644
--- a/gcc/testsuite/g++.dg/lto/20081219_1.C
+++ b/gcc/testsuite/g++.dg/lto/20081219_1.C
@@ -7,7 +7,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
 {
   using::mbstate_t;
   typedef int *__c_locale;
-  class locale
+  struct locale
   {
     class facet;
   };
diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
index 4ddb3854c64..e09ce01cdfc 100644
--- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C
+++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
@@ -14,7 +14,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
   typedef basic_ostream<char> ostream;
   template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
       class num_get;
-  class locale   {
+  struct locale   {
       class facet;
   };
   class locale::facet   {
diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
index 73686918c2c..4e3de7d6a34 100644
--- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C
+++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
@@ -24,7 +24,9 @@ namespace std
 {
 class locale
 {
+public:
     class facet;
+private:
     class _Impl;
     _Impl *_M_impl;
 };
@@ -70,6 +72,7 @@ class ios_base
     int _M_word_size;
     _Words *_M_word;
     locale _M_ios_locale;
+protected:
     virtual ~ ios_base ();
 };
 template < typename, typename > class istreambuf_iterator
diff --git a/gcc/testsuite/g++.dg/opt/dump1.C b/gcc/testsuite/g++.dg/opt/dump1.C
index 75d71110022..558bee00762 100644
--- a/gcc/testsuite/g++.dg/opt/dump1.C
+++ b/gcc/testsuite/g++.dg/opt/dump1.C
@@ -396,7 +396,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
     ;
   template<typename _Signature>
     class function;
-  class _Function_base
+  struct _Function_base
   {
     template<typename _Functor>
       class _Base_manager
diff --git a/gcc/testsuite/g++.dg/other/pr53574.C b/gcc/testsuite/g++.dg/other/pr53574.C
index cc899a552c8..87622d522ee 100644
--- a/gcc/testsuite/g++.dg/other/pr53574.C
+++ b/gcc/testsuite/g++.dg/other/pr53574.C
@@ -6,7 +6,7 @@ template <typename> struct A { typedef int type; };
 struct B {
   typedef __SIZE_TYPE__ H;
 };
-template <typename> class allocator : B {};
+template <typename> class allocator : public B {};
 template <typename _Alloc> struct C {
   template <typename T>
   static typename T::H foo(T *);
diff --git a/gcc/testsuite/g++.dg/template/access30.C b/gcc/testsuite/g++.dg/template/access30.C
new file mode 100644
index 00000000000..b03a99af1f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access30.C
@@ -0,0 +1,10 @@
+// PR c++/41437
+// { dg-do compile }
+
+class A { struct B { B(); }; };
+template<typename T> void f() { A::B b; } // { dg-error "private" }
+void g() { f<int>(); }
+
+class X { template<typename> struct A{}; };
+
+X::A<int> a; // { dg-error "private" }
diff --git a/gcc/testsuite/g++.dg/template/access31.C b/gcc/testsuite/g++.dg/template/access31.C
new file mode 100644
index 00000000000..0aa7dbbf8f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access31.C
@@ -0,0 +1,29 @@
+// PR c++/47346
+// { dg-do compile }
+
+class C
+{
+  struct Private { };
+};
+
+template<typename T>
+struct exploit1
+{
+    typedef C::Private type; // { dg-error "private" }
+};
+exploit1<int>::type x1;
+
+template<typename T>
+struct exploit2 : C::Private // { dg-error "private" }
+{
+};
+exploit2<int> x2;
+
+template<typename T>
+struct exploit3
+{
+    template<class U = C::Private> // { dg-error "private" }
+    struct E {};
+};
+
+exploit3<int>::E<> e;
diff --git a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
index 5072d1ad59d..1f9ad5fdb47 100644
--- a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
+++ b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
@@ -35,7 +35,7 @@ struct __alloc_traits    : allocator_traits<_Alloc>    {
   template<typename _Tp>       struct rebind       {   typedef typename _Base_type::template rebind_alloc<_Tp> other;   };
 };
 
-template<typename _Tp>     class allocator {
+template<typename _Tp>     struct allocator {
   typedef _Tp value_type;
   template<typename _Tp1>  struct rebind  {   typedef allocator<_Tp1> other;   };
 };
diff --git a/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
new file mode 100644
index 00000000000..80646b37f55
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <type_traits>
+
+class Class { Class() {} };
+
+template <typename X> static bool foo() {
+  return std::is_constructible<Class>::value;
+}
+
+static_assert(!std::is_constructible<Class>::value, "");
Patrick Palka June 15, 2020, 2:04 p.m. UTC | #3
On Mon, 15 Jun 2020, Patrick Palka wrote:

> On Thu, 11 Jun 2020, Jason Merrill wrote:
> 
> > On 6/5/20 5:16 PM, Patrick Palka wrote:
> > > This patch generalizes our existing functionality for deferring access
> > > checking of typedefs when parsing a function or class template to now
> > > defer all kinds of access checks until template instantiation time,
> > > including member function and member object accesses.
> > > 
> > > Since all access checks eventually go through enforce_access, the main
> > > component of this patch is new handling inside enforce_access to defer
> > > the current access check if we're inside a template.  The bulk of the
> > > rest of the patch consists of removing now-unneeded code pertaining to
> > > suppressing access checks inside templates or pertaining to
> > > typedef-specific access handling.  Renamings and other changes with no
> > > functional impact have been split off into the followup patch.
> > 
> > Great!
> > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
> > > building parts of boost, cmcstl2 and other libraries.
> > 
> > > -      && !dependent_type_p (qualifying_type))
> > > +      && !dependent_type_p (scope))
> > 
> > This needs a comment.  And it occurs to me that if we're only going to check
> > access if scope is non-dependent, we can check that much earlier and avoid the
> > need to guard DECL_NONSTATIC_MEMBER_P.
> 
> Good point, that works much better.  Done in the below patch, which has
> been bootstrapped and regtested  on x86_64-pc-linux-gnu and has been
> smoke tested on a number of libraries.  (The followup patch remains
> essentially unchanged.)
> 
> -- >8 --
> 
> Subject: [PATCH 1/2] c++: Improve access checking inside templates [PR41437]
> 
> This patch generalizes our existing functionality for deferring access
> checking of typedefs when parsing a function or class template to now
> defer all kinds of access checks until template instantiation time,
> including member function and member object accesses.
> 
> Since all access checks eventually go through enforce_access, the main
> component of this patch is new handling inside enforce_access to defer
> the current access check if we're inside a template.  The bulk of the
> rest of the patch consists of removing now-unneeded code pertaining to
> suppressing access checks inside templates or pertaining to
> typedef-specific access handling.  Renamings and other changes with no
> functional impact have been split off into the followup patch.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
> building parts of boost, cmcstl2 and other libraries.
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/41437
> 	PR c++/47346
> 	* call.c (enforce_access): Move to semantics.c.
> 	* cp-tree.h (enforce_access): Delete.
> 	(get_types_needing_access_check): Delete.
> 	(add_typedef_to_current_template_for_access_check): Delete.
> 	* decl.c (make_typename_type): Adjust accordingly.  Use
> 	check_accessibility_of_qualified_id instead of directly using
> 	perform_or_defer_access_check.
> 	* parser.c (cp_parser_template_declaration_after_parameters):
> 	Don't push a dk_no_check access state when parsing a template.
> 	* pt.c (get_types_needing_access_check): Delete.
> 	(append_type_to_template_for_access_check_1): Delete.
> 	(perform_typedefs_access_check): Adjust.  If type_decl is a
> 	FIELD_DECL, also check its DECL_CONTEXT for dependence. Use
> 	tsubst_copy instead of tsubst to substitute into type_decl so
> 	that we substitute into the DECL_CONTEXT of a FIELD_DECL.
> 	(append_type_to_template_for_access_check): Delete.
> 	* search.c (accessible_p): Remove the processing_template_decl
> 	early exit.
> 	* semantics.c (enforce_access): Moved from call.c.  If we're
> 	parsing a template and the access check failed, add the check to
> 	TI_TYPEDEFS_NEEDING_ACCESS_CHECKING.
> 	(perform_or_defer_access_check): Adjust comment.
> 	(add_typedef_to_current_template_for_access_check): Delete.
> 	(check_accessibility_of_qualified_id):  Adjust accordingly.
> 	Exit early if the scope is dependent.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/41437
> 	PR c++/47346
> 	* g++.dg/cpp2a/concepts-using2.C: Adjust.
> 	* g++.dg/lto/20081219_1.C: Adjust.
> 	* g++.dg/lto/20091002-1_0.C: Adjust.
> 	* g++.dg/lto/pr65475c_0.C: Adjust.
> 	* g++.dg/opt/dump1.C: Adjust.
> 	* g++.dg/other/pr53574.C: Adjust.
> 	* g++.dg/template/access30.C: New test.
> 	* g++.dg/template/access31.C: New test.
> 	* g++.dg/wrappers/wrapper-around-type-pack-expansion.C: Adjust.
> 
> libstdc++-v3/ChangeLog:
> 
> 	PR libstdc++/94003
> 	* testsuite/20_util/is_constructible/94003.cc: New test.
> ---
>  gcc/cp/call.c                                 |  36 -----
>  gcc/cp/cp-tree.h                              |   6 -
>  gcc/cp/decl.c                                 |   8 +-
>  gcc/cp/parser.c                               |   4 -
>  gcc/cp/pt.c                                   | 120 +----------------
>  gcc/cp/search.c                               |  15 ---
>  gcc/cp/semantics.c                            | 127 +++++++++++-------
>  gcc/testsuite/g++.dg/cpp2a/concepts-using2.C  |   4 +-
>  gcc/testsuite/g++.dg/lto/20081219_1.C         |   2 +-
>  gcc/testsuite/g++.dg/lto/20091002-1_0.C       |   2 +-
>  gcc/testsuite/g++.dg/lto/pr65475c_0.C         |   3 +
>  gcc/testsuite/g++.dg/opt/dump1.C              |   2 +-
>  gcc/testsuite/g++.dg/other/pr53574.C          |   2 +-
>  gcc/testsuite/g++.dg/template/access30.C      |  10 ++
>  gcc/testsuite/g++.dg/template/access31.C      |  29 ++++
>  .../wrapper-around-type-pack-expansion.C      |   2 +-
>  .../20_util/is_constructible/94003.cc         |  28 ++++
>  17 files changed, 159 insertions(+), 241 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/access30.C
>  create mode 100644 gcc/testsuite/g++.dg/template/access31.C
>  create mode 100644 libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
> 
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index b99959f76f9..b55dc83f0e7 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -7083,42 +7083,6 @@ complain_about_access (tree decl, tree diag_decl, bool issue_error)
>      }
>  }
>  
> -/* If the current scope isn't allowed to access DECL along
> -   BASETYPE_PATH, give an error.  The most derived class in
> -   BASETYPE_PATH is the one used to qualify DECL. DIAG_DECL is
> -   the declaration to use in the error diagnostic.  */
> -
> -bool
> -enforce_access (tree basetype_path, tree decl, tree diag_decl,
> -		tsubst_flags_t complain, access_failure_info *afi)
> -{
> -  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
> -
> -  if (flag_new_inheriting_ctors
> -      && DECL_INHERITED_CTOR (decl))
> -    {
> -      /* 7.3.3/18: The additional constructors are accessible if they would be
> -	 accessible when used to construct an object of the corresponding base
> -	 class.  */
> -      decl = strip_inheriting_ctors (decl);
> -      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
> -				   ba_any, NULL, complain);
> -    }
> -
> -  if (!accessible_p (basetype_path, decl, true))
> -    {
> -      if (flag_new_inheriting_ctors)
> -	diag_decl = strip_inheriting_ctors (diag_decl);
> -      if (complain & tf_error)
> -	complain_about_access (decl, diag_decl, true);
> -      if (afi)
> -	afi->record_access_failure (basetype_path, decl, diag_decl);
> -      return false;
> -    }
> -
> -  return true;
> -}
> -
>  /* Initialize a temporary of type TYPE with EXPR.  The FLAGS are a
>     bitwise or of LOOKUP_* values.  If any errors are warnings are
>     generated, set *DIAGNOSTIC_FN to "error" or "warning",
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 44cb10cfee5..771d51cc283 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6339,9 +6339,6 @@ class access_failure_info
>  };
>  
>  extern void complain_about_access		(tree, tree, bool);
> -extern bool enforce_access			(tree, tree, tree,
> -						 tsubst_flags_t,
> -						 access_failure_info *afi = NULL);
>  extern void push_defarg_context			(tree);
>  extern void pop_defarg_context			(void);
>  extern tree convert_default_arg			(tree, tree, tree, int,
> @@ -6939,7 +6936,6 @@ extern tree make_pack_expansion                 (tree, tsubst_flags_t = tf_warni
>  extern bool check_for_bare_parameter_packs      (tree, location_t = UNKNOWN_LOCATION);
>  extern tree build_template_info			(tree, tree);
>  extern tree get_template_info			(const_tree);
> -extern vec<qualified_typedef_usage_t, va_gc> *get_types_needing_access_check (tree);
>  extern int template_class_depth			(tree);
>  extern int is_specialization_of			(tree, tree);
>  extern bool is_specialization_of_friend		(tree, tree);
> @@ -7257,8 +7253,6 @@ extern void finish_mem_initializers		(tree);
>  extern tree check_template_template_default_arg (tree);
>  extern bool expand_or_defer_fn_1		(tree);
>  extern void expand_or_defer_fn			(tree);
> -extern void add_typedef_to_current_template_for_access_check (tree, tree,
> -							      location_t);
>  extern bool check_accessibility_of_qualified_id (tree, tree, tree, tsubst_flags_t);
>  extern tree finish_qualified_id_expr		(tree, tree, bool, bool,
>  						 bool, bool, tsubst_flags_t);
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index b8bd09b37e6..539609e8ada 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -4009,14 +4009,10 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
>        return error_mark_node;
>      }
>  
> -  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
> +  if (!check_accessibility_of_qualified_id (t, /*object_type=*/NULL_TREE,
> +					    context, complain))
>      return error_mark_node;
>  
> -  /* If we are currently parsing a template and if T is a typedef accessed
> -     through CONTEXT then we need to remember and check access of T at
> -     template instantiation time.  */
> -  add_typedef_to_current_template_for_access_check (t, context, input_location);
> -
>    if (want_template)
>      return lookup_template_class (t, TREE_OPERAND (fullname, 1),
>  				  NULL_TREE, context,
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index bc66e6e5c50..799f310bcee 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -29118,16 +29118,12 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
>      decl = cp_parser_concept_definition (parser);
>    else
>      {
> -      /* There are no access checks when parsing a template, as we do not
> -	 know if a specialization will be a friend.  */
> -      push_deferring_access_checks (dk_no_check);
>        cp_token *token = cp_lexer_peek_token (parser->lexer);
>        decl = cp_parser_single_declaration (parser,
>  					   checks,
>  					   member_p,
>                                             /*explicit_specialization_p=*/false,
>  					   &friend_p);
> -      pop_deferring_access_checks ();
>  
>        /* If this is a member template declaration, let the front
>  	 end know.  */
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index cdf6a3eeaf3..bab48c2fdf6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -216,8 +216,6 @@ static bool dependent_type_p_r (tree);
>  static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
>  static tree tsubst_decl (tree, tree, tsubst_flags_t);
>  static void perform_typedefs_access_check (tree tmpl, tree targs);
> -static void append_type_to_template_for_access_check_1 (tree, tree, tree,
> -							location_t);
>  static tree listify (tree);
>  static tree listify_autos (tree, tree);
>  static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
> @@ -11532,7 +11530,7 @@ perform_typedefs_access_check (tree tmpl, tree targs)
>      return;
>  
>    if (vec<qualified_typedef_usage_t, va_gc> *tdefs
> -      = get_types_needing_access_check (tmpl))
> +      = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (get_template_info (tmpl)))
>      FOR_EACH_VEC_ELT (*tdefs, i, iter)
>        {
>  	tree type_decl = iter->typedef_decl;
> @@ -11541,8 +11539,10 @@ perform_typedefs_access_check (tree tmpl, tree targs)
>  	if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
>  	  continue;
>  
> -	if (uses_template_parms (type_decl))
> -	  type_decl = tsubst (type_decl, targs, tf_error, NULL_TREE);
> +	if (uses_template_parms (type_decl)
> +	    || (TREE_CODE (type_decl) == FIELD_DECL
> +		&& uses_template_parms (DECL_CONTEXT (type_decl))))
> +	  type_decl = tsubst_copy (type_decl, targs, tf_error, NULL_TREE);
>  	if (uses_template_parms (type_scope))
>  	  type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
>  
> @@ -29154,116 +29154,6 @@ check_auto_in_tmpl_args (tree tmpl, tree args)
>    return errors;
>  }
>  
> -/* For a given template T, return the vector of typedefs referenced
> -   in T for which access check is needed at T instantiation time.
> -   T is either  a FUNCTION_DECL or a RECORD_TYPE.
> -   Those typedefs were added to T by the function
> -   append_type_to_template_for_access_check.  */
> -
> -vec<qualified_typedef_usage_t, va_gc> *
> -get_types_needing_access_check (tree t)
> -{
> -  gcc_checking_assert ((CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL));
> -  
> -  if (tree ti = get_template_info (t))
> -    if (TI_TEMPLATE (ti))
> -      return TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
> -
> -  return NULL;
> -}
> -
> -/* Append the typedef TYPE_DECL used in template T to a list of typedefs
> -   tied to T. That list of typedefs will be access checked at
> -   T instantiation time.
> -   T is either a FUNCTION_DECL or a RECORD_TYPE.
> -   TYPE_DECL is a TYPE_DECL node representing a typedef.
> -   SCOPE is the scope through which TYPE_DECL is accessed.
> -   LOCATION is the location of the usage point of TYPE_DECL.
> -
> -   This function is a subroutine of
> -   append_type_to_template_for_access_check.  */
> -
> -static void
> -append_type_to_template_for_access_check_1 (tree t,
> -					    tree type_decl,
> -					    tree scope,
> -					    location_t location)
> -{
> -  qualified_typedef_usage_t typedef_usage;
> -  tree ti;
> -
> -  if (!t || t == error_mark_node)
> -    return;
> -
> -  gcc_assert ((TREE_CODE (t) == FUNCTION_DECL
> -	       || CLASS_TYPE_P (t))
> -	      && type_decl
> -	      && TREE_CODE (type_decl) == TYPE_DECL
> -	      && scope);
> -
> -  if (!(ti = get_template_info (t)))
> -    return;
> -
> -  gcc_assert (TI_TEMPLATE (ti));
> -
> -  typedef_usage.typedef_decl = type_decl;
> -  typedef_usage.context = scope;
> -  typedef_usage.locus = location;
> -
> -  vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), typedef_usage);
> -}
> -
> -/* Append TYPE_DECL to the template TEMPL.
> -   TEMPL is either a class type, a FUNCTION_DECL or a TEMPLATE_DECL.
> -   At TEMPL instanciation time, TYPE_DECL will be checked to see
> -   if it can be accessed through SCOPE.
> -   LOCATION is the location of the usage point of TYPE_DECL.
> -
> -   e.g. consider the following code snippet:
> -
> -     class C
> -     {
> -       typedef int myint;
> -     };
> -
> -     template<class U> struct S
> -     {
> -       C::myint mi; // <-- usage point of the typedef C::myint
> -     };
> -
> -     S<char> s;
> -
> -   At S<char> instantiation time, we need to check the access of C::myint
> -   In other words, we need to check the access of the myint typedef through
> -   the C scope. For that purpose, this function will add the myint typedef
> -   and the scope C through which its being accessed to a list of typedefs
> -   tied to the template S. That list will be walked at template instantiation
> -   time and access check performed on each typedefs it contains.
> -   Note that this particular code snippet should yield an error because
> -   myint is private to C.  */
> -
> -void
> -append_type_to_template_for_access_check (tree templ,
> -                                          tree type_decl,
> -					  tree scope,
> -					  location_t location)
> -{
> -  qualified_typedef_usage_t *iter;
> -  unsigned i;
> -
> -  gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
> -
> -  /* Make sure we don't append the type to the template twice.  */
> -  if (vec<qualified_typedef_usage_t, va_gc> *tdefs
> -      = get_types_needing_access_check (templ))
> -    FOR_EACH_VEC_ELT (*tdefs, i, iter)
> -      if (iter->typedef_decl == type_decl && scope == iter->context)
> -	return;
> -
> -  append_type_to_template_for_access_check_1 (templ, type_decl,
> -					      scope, location);
> -}
> -
>  /* Recursively walk over && expressions searching for EXPR. Return a reference
>     to that expression.  */
>  
> diff --git a/gcc/cp/search.c b/gcc/cp/search.c
> index b9da2fccb7f..a1a45a5ee6b 100644
> --- a/gcc/cp/search.c
> +++ b/gcc/cp/search.c
> @@ -827,21 +827,6 @@ accessible_p (tree type, tree decl, bool consider_local_p)
>    if (current_function_decl && DECL_THUNK_P (current_function_decl))
>      return 1;
>  
> -  /* In a template declaration, we cannot be sure whether the
> -     particular specialization that is instantiated will be a friend
> -     or not.  Therefore, all access checks are deferred until
> -     instantiation.  However, PROCESSING_TEMPLATE_DECL is set in the
> -     parameter list for a template (because we may see dependent types
> -     in default arguments for template parameters), and access
> -     checking should be performed in the outermost parameter list.  */
> -  if (processing_template_decl
> -      /* FIXME CWG has been talking about doing access checking in the context
> -	 of the constraint-expression, rather than the constrained declaration,
> -	 in which case we would want to remove this test.  */
> -      && !processing_constraint_expression_p ()
> -      && (!processing_template_parmlist || processing_template_decl > 1))
> -    return 1;
> -
>    tree otype = NULL_TREE;
>    if (!TYPE_P (type))
>      {
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index 64587c791c6..97a37ca5d2b 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -256,6 +256,68 @@ pop_to_parent_deferring_access_checks (void)
>      }
>  }
>  
> +/* If the current scope isn't allowed to access DECL along
> +   BASETYPE_PATH, give an error, or if we're parsing a function or class
> +   template, defer the access check to be performed at instantiation time.
> +   The most derived class in BASETYPE_PATH is the one used to qualify DECL.
> +   DIAG_DECL is the declaration to use in the error diagnostic.  */
> +
> +static bool
> +enforce_access (tree basetype_path, tree decl, tree diag_decl,
> +		tsubst_flags_t complain, access_failure_info *afi = NULL)
> +{
> +  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
> +
> +  if (flag_new_inheriting_ctors
> +      && DECL_INHERITED_CTOR (decl))
> +    {
> +      /* 7.3.3/18: The additional constructors are accessible if they would be
> +	 accessible when used to construct an object of the corresponding base
> +	 class.  */
> +      decl = strip_inheriting_ctors (decl);
> +      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
> +				   ba_any, NULL, complain);
> +    }
> +
> +  tree cs = current_scope ();
> +  if (processing_template_decl
> +      && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
> +    if (tree template_info = get_template_info (cs))
> +      {
> +	/* When parsing a function or class template, we in general need to
> +	   defer access checks until template instantiation time, since a friend
> +	   declaration may grant access only to a particular specialization of
> +	   the template.  */
> +
> +	if (accessible_p (basetype_path, decl, /*consider_local_p=*/true))
> +	  /* But if the member is deemed accessible at parse time, then we can
> +	     assume it'll be accessible at instantiation time.  */
> +	  return true;
> +
> +	/* Defer this access check until instantiation time.  */
> +	qualified_typedef_usage_t typedef_usage;
> +	typedef_usage.typedef_decl = decl;
> +	typedef_usage.context = TREE_TYPE (basetype_path);
> +	typedef_usage.locus = input_location;
> +	vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (template_info),
> +		       typedef_usage);
> +	return true;
> +      }
> +
> +  if (!accessible_p (basetype_path, decl, /*consider_local_p=*/true))
> +    {
> +      if (flag_new_inheriting_ctors)
> +	diag_decl = strip_inheriting_ctors (diag_decl);
> +      if (complain & tf_error)
> +	complain_about_access (decl, diag_decl, true);
> +      if (afi)
> +	afi->record_access_failure (basetype_path, decl, diag_decl);
> +      return false;
> +    }
> +
> +  return true;
> +}
> +
>  /* Perform the access checks in CHECKS.  The TREE_PURPOSE of each node
>     is the BINFO indicating the qualifying scope used to access the
>     DECL node stored in the TREE_VALUE of the node.  If CHECKS is empty
> @@ -320,9 +382,7 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
>    deferred_access *ptr;
>    deferred_access_check *chk;
>  
> -
> -  /* Exit if we are in a context that no access checking is performed.
> -     */
> +  /* Exit if we are in a context that no access checking is performed.  */
>    if (deferred_access_no_check)
>      return true;
>  
> @@ -1992,37 +2052,6 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
>    return ret;
>  }
>  
> -/* If we are currently parsing a template and we encountered a typedef
> -   TYPEDEF_DECL that is being accessed though CONTEXT, this function
> -   adds the typedef to a list tied to the current template.
> -   At template instantiation time, that list is walked and access check
> -   performed for each typedef.
> -   LOCATION is the location of the usage point of TYPEDEF_DECL.  */
> -
> -void
> -add_typedef_to_current_template_for_access_check (tree typedef_decl,
> -                                                  tree context,
> -						  location_t location)
> -{
> -    tree template_info = NULL;
> -    tree cs = current_scope ();
> -
> -    if (!is_typedef_decl (typedef_decl)
> -	|| !context
> -	|| !CLASS_TYPE_P (context)
> -	|| !cs)
> -      return;
> -
> -    if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)
> -      template_info = get_template_info (cs);
> -
> -    if (template_info
> -	&& TI_TEMPLATE (template_info)
> -	&& !currently_open_class (context))
> -      append_type_to_template_for_access_check (cs, typedef_decl,
> -						context, location);
> -}
> -
>  /* DECL was the declaration to which a qualified-id resolved.  Issue
>     an error message if it is not accessible.  If OBJECT_TYPE is
>     non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
> @@ -2036,28 +2065,23 @@ check_accessibility_of_qualified_id (tree decl,
>  				     tree nested_name_specifier,
>  				     tsubst_flags_t complain)
>  {
> -  tree scope;
> -  tree qualifying_type = NULL_TREE;
> -
> -  /* If we are parsing a template declaration and if decl is a typedef,
> -     add it to a list tied to the template.
> -     At template instantiation time, that list will be walked and
> -     access check performed.  */
> -  add_typedef_to_current_template_for_access_check (decl,
> -						    nested_name_specifier
> -						    ? nested_name_specifier
> -						    : DECL_CONTEXT (decl),
> -						    input_location);
> -
>    /* If we're not checking, return immediately.  */
>    if (deferred_access_no_check)
>      return true;
>  
>    /* Determine the SCOPE of DECL.  */
> -  scope = context_for_name_lookup (decl);
> -  /* If the SCOPE is not a type, then DECL is not a member.  */
> -  if (!TYPE_P (scope))
> +  tree scope = context_for_name_lookup (decl);
> +  /* If the SCOPE is not a type, then DECL is not a member.  And if the
> +     SCOPE is dependent, then we'll perform this access check again after
> +     substitution.  */

Whoops, I forgot to undo the changes to the above comment after
splitting it out into the comment below.  Consider the changes to the
above comment undone.

> +  if (!TYPE_P (scope)
> +      /* If SCOPE is dependent then we can't perform this access check now,
> +	 and since we'll perform this access check again after substitution
> +	 there's no need to explicitly defer it.  */
> +      || dependent_type_p (scope))
>      return true;
> +
> +  tree qualifying_type = NULL_TREE;
>    /* Compute the scope through which DECL is being accessed.  */
>    if (object_type
>        /* OBJECT_TYPE might not be a class type; consider:
> @@ -2096,8 +2120,7 @@ check_accessibility_of_qualified_id (tree decl,
>    if (qualifying_type
>        /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
>  	 or similar in a default argument value.  */
> -      && CLASS_TYPE_P (qualifying_type)
> -      && !dependent_type_p (qualifying_type))
> +      && CLASS_TYPE_P (qualifying_type))
>      return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
>  					  decl, complain);
>  
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
> index 206b54a2883..b9a67f5d8da 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
> @@ -10,7 +10,7 @@ template <typename b> using g = typename f<b>::e;
>  struct b;
>  template <typename b> struct f { using e = b; };
>  template <typename ai> struct m { typedef g<ai> aj; };
> -template <typename b> class n { typedef typename m<b>::aj e; };
> +template <typename b> struct n { typedef typename m<b>::aj e; };
>  template <typename b> using an = typename n<b>::e;
>  template <typename> constexpr bool ao = c<true>::d;
>  template <typename> constexpr bool i = c<1>::d;
> @@ -38,7 +38,7 @@ template <typename da> concept de = dd<da>;
>  struct {
>    template <de da, typename b> void operator()(da, b);
>  } di;
> -class p {
> +struct p {
>    void begin();
>  };
>  template <typename> using df = p;
> diff --git a/gcc/testsuite/g++.dg/lto/20081219_1.C b/gcc/testsuite/g++.dg/lto/20081219_1.C
> index 1bb96ef37de..8d64a0212cb 100644
> --- a/gcc/testsuite/g++.dg/lto/20081219_1.C
> +++ b/gcc/testsuite/g++.dg/lto/20081219_1.C
> @@ -7,7 +7,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
>  {
>    using::mbstate_t;
>    typedef int *__c_locale;
> -  class locale
> +  struct locale
>    {
>      class facet;
>    };
> diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
> index 4ddb3854c64..e09ce01cdfc 100644
> --- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C
> +++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
> @@ -14,7 +14,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
>    typedef basic_ostream<char> ostream;
>    template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
>        class num_get;
> -  class locale   {
> +  struct locale   {
>        class facet;
>    };
>    class locale::facet   {
> diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
> index 73686918c2c..4e3de7d6a34 100644
> --- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C
> +++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
> @@ -24,7 +24,9 @@ namespace std
>  {
>  class locale
>  {
> +public:
>      class facet;
> +private:
>      class _Impl;
>      _Impl *_M_impl;
>  };
> @@ -70,6 +72,7 @@ class ios_base
>      int _M_word_size;
>      _Words *_M_word;
>      locale _M_ios_locale;
> +protected:
>      virtual ~ ios_base ();
>  };
>  template < typename, typename > class istreambuf_iterator
> diff --git a/gcc/testsuite/g++.dg/opt/dump1.C b/gcc/testsuite/g++.dg/opt/dump1.C
> index 75d71110022..558bee00762 100644
> --- a/gcc/testsuite/g++.dg/opt/dump1.C
> +++ b/gcc/testsuite/g++.dg/opt/dump1.C
> @@ -396,7 +396,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
>      ;
>    template<typename _Signature>
>      class function;
> -  class _Function_base
> +  struct _Function_base
>    {
>      template<typename _Functor>
>        class _Base_manager
> diff --git a/gcc/testsuite/g++.dg/other/pr53574.C b/gcc/testsuite/g++.dg/other/pr53574.C
> index cc899a552c8..87622d522ee 100644
> --- a/gcc/testsuite/g++.dg/other/pr53574.C
> +++ b/gcc/testsuite/g++.dg/other/pr53574.C
> @@ -6,7 +6,7 @@ template <typename> struct A { typedef int type; };
>  struct B {
>    typedef __SIZE_TYPE__ H;
>  };
> -template <typename> class allocator : B {};
> +template <typename> class allocator : public B {};
>  template <typename _Alloc> struct C {
>    template <typename T>
>    static typename T::H foo(T *);
> diff --git a/gcc/testsuite/g++.dg/template/access30.C b/gcc/testsuite/g++.dg/template/access30.C
> new file mode 100644
> index 00000000000..b03a99af1f0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/access30.C
> @@ -0,0 +1,10 @@
> +// PR c++/41437
> +// { dg-do compile }
> +
> +class A { struct B { B(); }; };
> +template<typename T> void f() { A::B b; } // { dg-error "private" }
> +void g() { f<int>(); }
> +
> +class X { template<typename> struct A{}; };
> +
> +X::A<int> a; // { dg-error "private" }
> diff --git a/gcc/testsuite/g++.dg/template/access31.C b/gcc/testsuite/g++.dg/template/access31.C
> new file mode 100644
> index 00000000000..0aa7dbbf8f1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/access31.C
> @@ -0,0 +1,29 @@
> +// PR c++/47346
> +// { dg-do compile }
> +
> +class C
> +{
> +  struct Private { };
> +};
> +
> +template<typename T>
> +struct exploit1
> +{
> +    typedef C::Private type; // { dg-error "private" }
> +};
> +exploit1<int>::type x1;
> +
> +template<typename T>
> +struct exploit2 : C::Private // { dg-error "private" }
> +{
> +};
> +exploit2<int> x2;
> +
> +template<typename T>
> +struct exploit3
> +{
> +    template<class U = C::Private> // { dg-error "private" }
> +    struct E {};
> +};
> +
> +exploit3<int>::E<> e;
> diff --git a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
> index 5072d1ad59d..1f9ad5fdb47 100644
> --- a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
> +++ b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
> @@ -35,7 +35,7 @@ struct __alloc_traits    : allocator_traits<_Alloc>    {
>    template<typename _Tp>       struct rebind       {   typedef typename _Base_type::template rebind_alloc<_Tp> other;   };
>  };
>  
> -template<typename _Tp>     class allocator {
> +template<typename _Tp>     struct allocator {
>    typedef _Tp value_type;
>    template<typename _Tp1>  struct rebind  {   typedef allocator<_Tp1> other;   };
>  };
> diff --git a/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
> new file mode 100644
> index 00000000000..80646b37f55
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
> @@ -0,0 +1,28 @@
> +// Copyright (C) 2020 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// You should have received a copy of the GNU General Public License along
> +// with this library; see the file COPYING3.  If not see
> +// <http://www.gnu.org/licenses/>.
> +
> +// { dg-do compile { target c++11 } }
> +
> +#include <type_traits>
> +
> +class Class { Class() {} };
> +
> +template <typename X> static bool foo() {
> +  return std::is_constructible<Class>::value;
> +}
> +
> +static_assert(!std::is_constructible<Class>::value, "");
> -- 
> 2.27.0.83.g0313f36c6e
> 
>
Jason Merrill June 15, 2020, 4:35 p.m. UTC | #4
On 6/15/20 9:56 AM, Patrick Palka wrote:
> On Thu, 11 Jun 2020, Jason Merrill wrote:
> 
>> On 6/5/20 5:16 PM, Patrick Palka wrote:
>>> This patch generalizes our existing functionality for deferring access
>>> checking of typedefs when parsing a function or class template to now
>>> defer all kinds of access checks until template instantiation time,
>>> including member function and member object accesses.
>>>
>>> Since all access checks eventually go through enforce_access, the main
>>> component of this patch is new handling inside enforce_access to defer
>>> the current access check if we're inside a template.  The bulk of the
>>> rest of the patch consists of removing now-unneeded code pertaining to
>>> suppressing access checks inside templates or pertaining to
>>> typedef-specific access handling.  Renamings and other changes with no
>>> functional impact have been split off into the followup patch.
>>
>> Great!
>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
>>> building parts of boost, cmcstl2 and other libraries.
>>
>>> -      && !dependent_type_p (qualifying_type))
>>> +      && !dependent_type_p (scope))
>>
>> This needs a comment.  And it occurs to me that if we're only going to check
>> access if scope is non-dependent, we can check that much earlier and avoid the
>> need to guard DECL_NONSTATIC_MEMBER_P.
> 
> Good point, that works much better.  Done in the below patch, which has
> been bootstrapped and regtested  on x86_64-pc-linux-gnu and has been
> smoke tested on a number of libraries.

OK, thanks.

> (The followup patch remains
> essentially unchanged.)
> 
> -- >8 --
> 
> Subject: [PATCH 1/2] c++: Improve access checking inside templates [PR41437]
> 
> This patch generalizes our existing functionality for deferring access
> checking of typedefs when parsing a function or class template to now
> defer all kinds of access checks until template instantiation time,
> including member function and member object accesses.
> 
> Since all access checks eventually go through enforce_access, the main
> component of this patch is new handling inside enforce_access to defer
> the current access check if we're inside a template.  The bulk of the
> rest of the patch consists of removing now-unneeded code pertaining to
> suppressing access checks inside templates or pertaining to
> typedef-specific access handling.  Renamings and other changes with no
> functional impact have been split off into the followup patch.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested by
> building parts of boost, cmcstl2 and other libraries.
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/41437
> 	PR c++/47346
> 	* call.c (enforce_access): Move to semantics.c.
> 	* cp-tree.h (enforce_access): Delete.
> 	(get_types_needing_access_check): Delete.
> 	(add_typedef_to_current_template_for_access_check): Delete.
> 	* decl.c (make_typename_type): Adjust accordingly.  Use
> 	check_accessibility_of_qualified_id instead of directly using
> 	perform_or_defer_access_check.
> 	* parser.c (cp_parser_template_declaration_after_parameters):
> 	Don't push a dk_no_check access state when parsing a template.
> 	* pt.c (get_types_needing_access_check): Delete.
> 	(append_type_to_template_for_access_check_1): Delete.
> 	(perform_typedefs_access_check): Adjust.  If type_decl is a
> 	FIELD_DECL, also check its DECL_CONTEXT for dependence. Use
> 	tsubst_copy instead of tsubst to substitute into type_decl so
> 	that we substitute into the DECL_CONTEXT of a FIELD_DECL.
> 	(append_type_to_template_for_access_check): Delete.
> 	* search.c (accessible_p): Remove the processing_template_decl
> 	early exit.
> 	* semantics.c (enforce_access): Moved from call.c.  If we're
> 	parsing a template and the access check failed, add the check to
> 	TI_TYPEDEFS_NEEDING_ACCESS_CHECKING.
> 	(perform_or_defer_access_check): Adjust comment.
> 	(add_typedef_to_current_template_for_access_check): Delete.
> 	(check_accessibility_of_qualified_id):  Adjust accordingly.
> 	Exit early if the scope is dependent.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/41437
> 	PR c++/47346
> 	* g++.dg/cpp2a/concepts-using2.C: Adjust.
> 	* g++.dg/lto/20081219_1.C: Adjust.
> 	* g++.dg/lto/20091002-1_0.C: Adjust.
> 	* g++.dg/lto/pr65475c_0.C: Adjust.
> 	* g++.dg/opt/dump1.C: Adjust.
> 	* g++.dg/other/pr53574.C: Adjust.
> 	* g++.dg/template/access30.C: New test.
> 	* g++.dg/template/access31.C: New test.
> 	* g++.dg/wrappers/wrapper-around-type-pack-expansion.C: Adjust.
> 
> libstdc++-v3/ChangeLog:
> 
> 	PR libstdc++/94003
> 	* testsuite/20_util/is_constructible/94003.cc: New test.
> ---
>   gcc/cp/call.c                                 |  36 -----
>   gcc/cp/cp-tree.h                              |   6 -
>   gcc/cp/decl.c                                 |   8 +-
>   gcc/cp/parser.c                               |   4 -
>   gcc/cp/pt.c                                   | 120 +----------------
>   gcc/cp/search.c                               |  15 ---
>   gcc/cp/semantics.c                            | 127 +++++++++++-------
>   gcc/testsuite/g++.dg/cpp2a/concepts-using2.C  |   4 +-
>   gcc/testsuite/g++.dg/lto/20081219_1.C         |   2 +-
>   gcc/testsuite/g++.dg/lto/20091002-1_0.C       |   2 +-
>   gcc/testsuite/g++.dg/lto/pr65475c_0.C         |   3 +
>   gcc/testsuite/g++.dg/opt/dump1.C              |   2 +-
>   gcc/testsuite/g++.dg/other/pr53574.C          |   2 +-
>   gcc/testsuite/g++.dg/template/access30.C      |  10 ++
>   gcc/testsuite/g++.dg/template/access31.C      |  29 ++++
>   .../wrapper-around-type-pack-expansion.C      |   2 +-
>   .../20_util/is_constructible/94003.cc         |  28 ++++
>   17 files changed, 159 insertions(+), 241 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/template/access30.C
>   create mode 100644 gcc/testsuite/g++.dg/template/access31.C
>   create mode 100644 libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
> 
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index b99959f76f9..b55dc83f0e7 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -7083,42 +7083,6 @@ complain_about_access (tree decl, tree diag_decl, bool issue_error)
>       }
>   }
>   
> -/* If the current scope isn't allowed to access DECL along
> -   BASETYPE_PATH, give an error.  The most derived class in
> -   BASETYPE_PATH is the one used to qualify DECL. DIAG_DECL is
> -   the declaration to use in the error diagnostic.  */
> -
> -bool
> -enforce_access (tree basetype_path, tree decl, tree diag_decl,
> -		tsubst_flags_t complain, access_failure_info *afi)
> -{
> -  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
> -
> -  if (flag_new_inheriting_ctors
> -      && DECL_INHERITED_CTOR (decl))
> -    {
> -      /* 7.3.3/18: The additional constructors are accessible if they would be
> -	 accessible when used to construct an object of the corresponding base
> -	 class.  */
> -      decl = strip_inheriting_ctors (decl);
> -      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
> -				   ba_any, NULL, complain);
> -    }
> -
> -  if (!accessible_p (basetype_path, decl, true))
> -    {
> -      if (flag_new_inheriting_ctors)
> -	diag_decl = strip_inheriting_ctors (diag_decl);
> -      if (complain & tf_error)
> -	complain_about_access (decl, diag_decl, true);
> -      if (afi)
> -	afi->record_access_failure (basetype_path, decl, diag_decl);
> -      return false;
> -    }
> -
> -  return true;
> -}
> -
>   /* Initialize a temporary of type TYPE with EXPR.  The FLAGS are a
>      bitwise or of LOOKUP_* values.  If any errors are warnings are
>      generated, set *DIAGNOSTIC_FN to "error" or "warning",
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 44cb10cfee5..771d51cc283 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6339,9 +6339,6 @@ class access_failure_info
>   };
>   
>   extern void complain_about_access		(tree, tree, bool);
> -extern bool enforce_access			(tree, tree, tree,
> -						 tsubst_flags_t,
> -						 access_failure_info *afi = NULL);
>   extern void push_defarg_context			(tree);
>   extern void pop_defarg_context			(void);
>   extern tree convert_default_arg			(tree, tree, tree, int,
> @@ -6939,7 +6936,6 @@ extern tree make_pack_expansion                 (tree, tsubst_flags_t = tf_warni
>   extern bool check_for_bare_parameter_packs      (tree, location_t = UNKNOWN_LOCATION);
>   extern tree build_template_info			(tree, tree);
>   extern tree get_template_info			(const_tree);
> -extern vec<qualified_typedef_usage_t, va_gc> *get_types_needing_access_check (tree);
>   extern int template_class_depth			(tree);
>   extern int is_specialization_of			(tree, tree);
>   extern bool is_specialization_of_friend		(tree, tree);
> @@ -7257,8 +7253,6 @@ extern void finish_mem_initializers		(tree);
>   extern tree check_template_template_default_arg (tree);
>   extern bool expand_or_defer_fn_1		(tree);
>   extern void expand_or_defer_fn			(tree);
> -extern void add_typedef_to_current_template_for_access_check (tree, tree,
> -							      location_t);
>   extern bool check_accessibility_of_qualified_id (tree, tree, tree, tsubst_flags_t);
>   extern tree finish_qualified_id_expr		(tree, tree, bool, bool,
>   						 bool, bool, tsubst_flags_t);
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index b8bd09b37e6..539609e8ada 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -4009,14 +4009,10 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
>         return error_mark_node;
>       }
>   
> -  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
> +  if (!check_accessibility_of_qualified_id (t, /*object_type=*/NULL_TREE,
> +					    context, complain))
>       return error_mark_node;
>   
> -  /* If we are currently parsing a template and if T is a typedef accessed
> -     through CONTEXT then we need to remember and check access of T at
> -     template instantiation time.  */
> -  add_typedef_to_current_template_for_access_check (t, context, input_location);
> -
>     if (want_template)
>       return lookup_template_class (t, TREE_OPERAND (fullname, 1),
>   				  NULL_TREE, context,
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index bc66e6e5c50..799f310bcee 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -29118,16 +29118,12 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
>       decl = cp_parser_concept_definition (parser);
>     else
>       {
> -      /* There are no access checks when parsing a template, as we do not
> -	 know if a specialization will be a friend.  */
> -      push_deferring_access_checks (dk_no_check);
>         cp_token *token = cp_lexer_peek_token (parser->lexer);
>         decl = cp_parser_single_declaration (parser,
>   					   checks,
>   					   member_p,
>                                              /*explicit_specialization_p=*/false,
>   					   &friend_p);
> -      pop_deferring_access_checks ();
>   
>         /* If this is a member template declaration, let the front
>   	 end know.  */
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index cdf6a3eeaf3..bab48c2fdf6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -216,8 +216,6 @@ static bool dependent_type_p_r (tree);
>   static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
>   static tree tsubst_decl (tree, tree, tsubst_flags_t);
>   static void perform_typedefs_access_check (tree tmpl, tree targs);
> -static void append_type_to_template_for_access_check_1 (tree, tree, tree,
> -							location_t);
>   static tree listify (tree);
>   static tree listify_autos (tree, tree);
>   static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
> @@ -11532,7 +11530,7 @@ perform_typedefs_access_check (tree tmpl, tree targs)
>       return;
>   
>     if (vec<qualified_typedef_usage_t, va_gc> *tdefs
> -      = get_types_needing_access_check (tmpl))
> +      = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (get_template_info (tmpl)))
>       FOR_EACH_VEC_ELT (*tdefs, i, iter)
>         {
>   	tree type_decl = iter->typedef_decl;
> @@ -11541,8 +11539,10 @@ perform_typedefs_access_check (tree tmpl, tree targs)
>   	if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
>   	  continue;
>   
> -	if (uses_template_parms (type_decl))
> -	  type_decl = tsubst (type_decl, targs, tf_error, NULL_TREE);
> +	if (uses_template_parms (type_decl)
> +	    || (TREE_CODE (type_decl) == FIELD_DECL
> +		&& uses_template_parms (DECL_CONTEXT (type_decl))))
> +	  type_decl = tsubst_copy (type_decl, targs, tf_error, NULL_TREE);
>   	if (uses_template_parms (type_scope))
>   	  type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
>   
> @@ -29154,116 +29154,6 @@ check_auto_in_tmpl_args (tree tmpl, tree args)
>     return errors;
>   }
>   
> -/* For a given template T, return the vector of typedefs referenced
> -   in T for which access check is needed at T instantiation time.
> -   T is either  a FUNCTION_DECL or a RECORD_TYPE.
> -   Those typedefs were added to T by the function
> -   append_type_to_template_for_access_check.  */
> -
> -vec<qualified_typedef_usage_t, va_gc> *
> -get_types_needing_access_check (tree t)
> -{
> -  gcc_checking_assert ((CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL));
> -
> -  if (tree ti = get_template_info (t))
> -    if (TI_TEMPLATE (ti))
> -      return TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
> -
> -  return NULL;
> -}
> -
> -/* Append the typedef TYPE_DECL used in template T to a list of typedefs
> -   tied to T. That list of typedefs will be access checked at
> -   T instantiation time.
> -   T is either a FUNCTION_DECL or a RECORD_TYPE.
> -   TYPE_DECL is a TYPE_DECL node representing a typedef.
> -   SCOPE is the scope through which TYPE_DECL is accessed.
> -   LOCATION is the location of the usage point of TYPE_DECL.
> -
> -   This function is a subroutine of
> -   append_type_to_template_for_access_check.  */
> -
> -static void
> -append_type_to_template_for_access_check_1 (tree t,
> -					    tree type_decl,
> -					    tree scope,
> -					    location_t location)
> -{
> -  qualified_typedef_usage_t typedef_usage;
> -  tree ti;
> -
> -  if (!t || t == error_mark_node)
> -    return;
> -
> -  gcc_assert ((TREE_CODE (t) == FUNCTION_DECL
> -	       || CLASS_TYPE_P (t))
> -	      && type_decl
> -	      && TREE_CODE (type_decl) == TYPE_DECL
> -	      && scope);
> -
> -  if (!(ti = get_template_info (t)))
> -    return;
> -
> -  gcc_assert (TI_TEMPLATE (ti));
> -
> -  typedef_usage.typedef_decl = type_decl;
> -  typedef_usage.context = scope;
> -  typedef_usage.locus = location;
> -
> -  vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), typedef_usage);
> -}
> -
> -/* Append TYPE_DECL to the template TEMPL.
> -   TEMPL is either a class type, a FUNCTION_DECL or a TEMPLATE_DECL.
> -   At TEMPL instanciation time, TYPE_DECL will be checked to see
> -   if it can be accessed through SCOPE.
> -   LOCATION is the location of the usage point of TYPE_DECL.
> -
> -   e.g. consider the following code snippet:
> -
> -     class C
> -     {
> -       typedef int myint;
> -     };
> -
> -     template<class U> struct S
> -     {
> -       C::myint mi; // <-- usage point of the typedef C::myint
> -     };
> -
> -     S<char> s;
> -
> -   At S<char> instantiation time, we need to check the access of C::myint
> -   In other words, we need to check the access of the myint typedef through
> -   the C scope. For that purpose, this function will add the myint typedef
> -   and the scope C through which its being accessed to a list of typedefs
> -   tied to the template S. That list will be walked at template instantiation
> -   time and access check performed on each typedefs it contains.
> -   Note that this particular code snippet should yield an error because
> -   myint is private to C.  */
> -
> -void
> -append_type_to_template_for_access_check (tree templ,
> -                                          tree type_decl,
> -					  tree scope,
> -					  location_t location)
> -{
> -  qualified_typedef_usage_t *iter;
> -  unsigned i;
> -
> -  gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
> -
> -  /* Make sure we don't append the type to the template twice.  */
> -  if (vec<qualified_typedef_usage_t, va_gc> *tdefs
> -      = get_types_needing_access_check (templ))
> -    FOR_EACH_VEC_ELT (*tdefs, i, iter)
> -      if (iter->typedef_decl == type_decl && scope == iter->context)
> -	return;
> -
> -  append_type_to_template_for_access_check_1 (templ, type_decl,
> -					      scope, location);
> -}
> -
>   /* Recursively walk over && expressions searching for EXPR. Return a reference
>      to that expression.  */
>   
> diff --git a/gcc/cp/search.c b/gcc/cp/search.c
> index b9da2fccb7f..a1a45a5ee6b 100644
> --- a/gcc/cp/search.c
> +++ b/gcc/cp/search.c
> @@ -827,21 +827,6 @@ accessible_p (tree type, tree decl, bool consider_local_p)
>     if (current_function_decl && DECL_THUNK_P (current_function_decl))
>       return 1;
>   
> -  /* In a template declaration, we cannot be sure whether the
> -     particular specialization that is instantiated will be a friend
> -     or not.  Therefore, all access checks are deferred until
> -     instantiation.  However, PROCESSING_TEMPLATE_DECL is set in the
> -     parameter list for a template (because we may see dependent types
> -     in default arguments for template parameters), and access
> -     checking should be performed in the outermost parameter list.  */
> -  if (processing_template_decl
> -      /* FIXME CWG has been talking about doing access checking in the context
> -	 of the constraint-expression, rather than the constrained declaration,
> -	 in which case we would want to remove this test.  */
> -      && !processing_constraint_expression_p ()
> -      && (!processing_template_parmlist || processing_template_decl > 1))
> -    return 1;
> -
>     tree otype = NULL_TREE;
>     if (!TYPE_P (type))
>       {
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index 64587c791c6..97a37ca5d2b 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -256,6 +256,68 @@ pop_to_parent_deferring_access_checks (void)
>       }
>   }
>   
> +/* If the current scope isn't allowed to access DECL along
> +   BASETYPE_PATH, give an error, or if we're parsing a function or class
> +   template, defer the access check to be performed at instantiation time.
> +   The most derived class in BASETYPE_PATH is the one used to qualify DECL.
> +   DIAG_DECL is the declaration to use in the error diagnostic.  */
> +
> +static bool
> +enforce_access (tree basetype_path, tree decl, tree diag_decl,
> +		tsubst_flags_t complain, access_failure_info *afi = NULL)
> +{
> +  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
> +
> +  if (flag_new_inheriting_ctors
> +      && DECL_INHERITED_CTOR (decl))
> +    {
> +      /* 7.3.3/18: The additional constructors are accessible if they would be
> +	 accessible when used to construct an object of the corresponding base
> +	 class.  */
> +      decl = strip_inheriting_ctors (decl);
> +      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
> +				   ba_any, NULL, complain);
> +    }
> +
> +  tree cs = current_scope ();
> +  if (processing_template_decl
> +      && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
> +    if (tree template_info = get_template_info (cs))
> +      {
> +	/* When parsing a function or class template, we in general need to
> +	   defer access checks until template instantiation time, since a friend
> +	   declaration may grant access only to a particular specialization of
> +	   the template.  */
> +
> +	if (accessible_p (basetype_path, decl, /*consider_local_p=*/true))
> +	  /* But if the member is deemed accessible at parse time, then we can
> +	     assume it'll be accessible at instantiation time.  */
> +	  return true;
> +
> +	/* Defer this access check until instantiation time.  */
> +	qualified_typedef_usage_t typedef_usage;
> +	typedef_usage.typedef_decl = decl;
> +	typedef_usage.context = TREE_TYPE (basetype_path);
> +	typedef_usage.locus = input_location;
> +	vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (template_info),
> +		       typedef_usage);
> +	return true;
> +      }
> +
> +  if (!accessible_p (basetype_path, decl, /*consider_local_p=*/true))
> +    {
> +      if (flag_new_inheriting_ctors)
> +	diag_decl = strip_inheriting_ctors (diag_decl);
> +      if (complain & tf_error)
> +	complain_about_access (decl, diag_decl, true);
> +      if (afi)
> +	afi->record_access_failure (basetype_path, decl, diag_decl);
> +      return false;
> +    }
> +
> +  return true;
> +}
> +
>   /* Perform the access checks in CHECKS.  The TREE_PURPOSE of each node
>      is the BINFO indicating the qualifying scope used to access the
>      DECL node stored in the TREE_VALUE of the node.  If CHECKS is empty
> @@ -320,9 +382,7 @@ perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
>     deferred_access *ptr;
>     deferred_access_check *chk;
>   
> -
> -  /* Exit if we are in a context that no access checking is performed.
> -     */
> +  /* Exit if we are in a context that no access checking is performed.  */
>     if (deferred_access_no_check)
>       return true;
>   
> @@ -1992,37 +2052,6 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
>     return ret;
>   }
>   
> -/* If we are currently parsing a template and we encountered a typedef
> -   TYPEDEF_DECL that is being accessed though CONTEXT, this function
> -   adds the typedef to a list tied to the current template.
> -   At template instantiation time, that list is walked and access check
> -   performed for each typedef.
> -   LOCATION is the location of the usage point of TYPEDEF_DECL.  */
> -
> -void
> -add_typedef_to_current_template_for_access_check (tree typedef_decl,
> -                                                  tree context,
> -						  location_t location)
> -{
> -    tree template_info = NULL;
> -    tree cs = current_scope ();
> -
> -    if (!is_typedef_decl (typedef_decl)
> -	|| !context
> -	|| !CLASS_TYPE_P (context)
> -	|| !cs)
> -      return;
> -
> -    if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)
> -      template_info = get_template_info (cs);
> -
> -    if (template_info
> -	&& TI_TEMPLATE (template_info)
> -	&& !currently_open_class (context))
> -      append_type_to_template_for_access_check (cs, typedef_decl,
> -						context, location);
> -}
> -
>   /* DECL was the declaration to which a qualified-id resolved.  Issue
>      an error message if it is not accessible.  If OBJECT_TYPE is
>      non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
> @@ -2036,28 +2065,23 @@ check_accessibility_of_qualified_id (tree decl,
>   				     tree nested_name_specifier,
>   				     tsubst_flags_t complain)
>   {
> -  tree scope;
> -  tree qualifying_type = NULL_TREE;
> -
> -  /* If we are parsing a template declaration and if decl is a typedef,
> -     add it to a list tied to the template.
> -     At template instantiation time, that list will be walked and
> -     access check performed.  */
> -  add_typedef_to_current_template_for_access_check (decl,
> -						    nested_name_specifier
> -						    ? nested_name_specifier
> -						    : DECL_CONTEXT (decl),
> -						    input_location);
> -
>     /* If we're not checking, return immediately.  */
>     if (deferred_access_no_check)
>       return true;
>   
>     /* Determine the SCOPE of DECL.  */
> -  scope = context_for_name_lookup (decl);
> -  /* If the SCOPE is not a type, then DECL is not a member.  */
> -  if (!TYPE_P (scope))
> +  tree scope = context_for_name_lookup (decl);
> +  /* If the SCOPE is not a type, then DECL is not a member.  And if the
> +     SCOPE is dependent, then we'll perform this access check again after
> +     substitution.  */
> +  if (!TYPE_P (scope)
> +      /* If SCOPE is dependent then we can't perform this access check now,
> +	 and since we'll perform this access check again after substitution
> +	 there's no need to explicitly defer it.  */
> +      || dependent_type_p (scope))
>       return true;
> +
> +  tree qualifying_type = NULL_TREE;
>     /* Compute the scope through which DECL is being accessed.  */
>     if (object_type
>         /* OBJECT_TYPE might not be a class type; consider:
> @@ -2096,8 +2120,7 @@ check_accessibility_of_qualified_id (tree decl,
>     if (qualifying_type
>         /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
>   	 or similar in a default argument value.  */
> -      && CLASS_TYPE_P (qualifying_type)
> -      && !dependent_type_p (qualifying_type))
> +      && CLASS_TYPE_P (qualifying_type))
>       return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
>   					  decl, complain);
>   
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
> index 206b54a2883..b9a67f5d8da 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
> @@ -10,7 +10,7 @@ template <typename b> using g = typename f<b>::e;
>   struct b;
>   template <typename b> struct f { using e = b; };
>   template <typename ai> struct m { typedef g<ai> aj; };
> -template <typename b> class n { typedef typename m<b>::aj e; };
> +template <typename b> struct n { typedef typename m<b>::aj e; };
>   template <typename b> using an = typename n<b>::e;
>   template <typename> constexpr bool ao = c<true>::d;
>   template <typename> constexpr bool i = c<1>::d;
> @@ -38,7 +38,7 @@ template <typename da> concept de = dd<da>;
>   struct {
>     template <de da, typename b> void operator()(da, b);
>   } di;
> -class p {
> +struct p {
>     void begin();
>   };
>   template <typename> using df = p;
> diff --git a/gcc/testsuite/g++.dg/lto/20081219_1.C b/gcc/testsuite/g++.dg/lto/20081219_1.C
> index 1bb96ef37de..8d64a0212cb 100644
> --- a/gcc/testsuite/g++.dg/lto/20081219_1.C
> +++ b/gcc/testsuite/g++.dg/lto/20081219_1.C
> @@ -7,7 +7,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
>   {
>     using::mbstate_t;
>     typedef int *__c_locale;
> -  class locale
> +  struct locale
>     {
>       class facet;
>     };
> diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
> index 4ddb3854c64..e09ce01cdfc 100644
> --- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C
> +++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
> @@ -14,7 +14,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
>     typedef basic_ostream<char> ostream;
>     template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
>         class num_get;
> -  class locale   {
> +  struct locale   {
>         class facet;
>     };
>     class locale::facet   {
> diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
> index 73686918c2c..4e3de7d6a34 100644
> --- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C
> +++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
> @@ -24,7 +24,9 @@ namespace std
>   {
>   class locale
>   {
> +public:
>       class facet;
> +private:
>       class _Impl;
>       _Impl *_M_impl;
>   };
> @@ -70,6 +72,7 @@ class ios_base
>       int _M_word_size;
>       _Words *_M_word;
>       locale _M_ios_locale;
> +protected:
>       virtual ~ ios_base ();
>   };
>   template < typename, typename > class istreambuf_iterator
> diff --git a/gcc/testsuite/g++.dg/opt/dump1.C b/gcc/testsuite/g++.dg/opt/dump1.C
> index 75d71110022..558bee00762 100644
> --- a/gcc/testsuite/g++.dg/opt/dump1.C
> +++ b/gcc/testsuite/g++.dg/opt/dump1.C
> @@ -396,7 +396,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
>       ;
>     template<typename _Signature>
>       class function;
> -  class _Function_base
> +  struct _Function_base
>     {
>       template<typename _Functor>
>         class _Base_manager
> diff --git a/gcc/testsuite/g++.dg/other/pr53574.C b/gcc/testsuite/g++.dg/other/pr53574.C
> index cc899a552c8..87622d522ee 100644
> --- a/gcc/testsuite/g++.dg/other/pr53574.C
> +++ b/gcc/testsuite/g++.dg/other/pr53574.C
> @@ -6,7 +6,7 @@ template <typename> struct A { typedef int type; };
>   struct B {
>     typedef __SIZE_TYPE__ H;
>   };
> -template <typename> class allocator : B {};
> +template <typename> class allocator : public B {};
>   template <typename _Alloc> struct C {
>     template <typename T>
>     static typename T::H foo(T *);
> diff --git a/gcc/testsuite/g++.dg/template/access30.C b/gcc/testsuite/g++.dg/template/access30.C
> new file mode 100644
> index 00000000000..b03a99af1f0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/access30.C
> @@ -0,0 +1,10 @@
> +// PR c++/41437
> +// { dg-do compile }
> +
> +class A { struct B { B(); }; };
> +template<typename T> void f() { A::B b; } // { dg-error "private" }
> +void g() { f<int>(); }
> +
> +class X { template<typename> struct A{}; };
> +
> +X::A<int> a; // { dg-error "private" }
> diff --git a/gcc/testsuite/g++.dg/template/access31.C b/gcc/testsuite/g++.dg/template/access31.C
> new file mode 100644
> index 00000000000..0aa7dbbf8f1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/access31.C
> @@ -0,0 +1,29 @@
> +// PR c++/47346
> +// { dg-do compile }
> +
> +class C
> +{
> +  struct Private { };
> +};
> +
> +template<typename T>
> +struct exploit1
> +{
> +    typedef C::Private type; // { dg-error "private" }
> +};
> +exploit1<int>::type x1;
> +
> +template<typename T>
> +struct exploit2 : C::Private // { dg-error "private" }
> +{
> +};
> +exploit2<int> x2;
> +
> +template<typename T>
> +struct exploit3
> +{
> +    template<class U = C::Private> // { dg-error "private" }
> +    struct E {};
> +};
> +
> +exploit3<int>::E<> e;
> diff --git a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
> index 5072d1ad59d..1f9ad5fdb47 100644
> --- a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
> +++ b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
> @@ -35,7 +35,7 @@ struct __alloc_traits    : allocator_traits<_Alloc>    {
>     template<typename _Tp>       struct rebind       {   typedef typename _Base_type::template rebind_alloc<_Tp> other;   };
>   };
>   
> -template<typename _Tp>     class allocator {
> +template<typename _Tp>     struct allocator {
>     typedef _Tp value_type;
>     template<typename _Tp1>  struct rebind  {   typedef allocator<_Tp1> other;   };
>   };
> diff --git a/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
> new file mode 100644
> index 00000000000..80646b37f55
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
> @@ -0,0 +1,28 @@
> +// Copyright (C) 2020 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// You should have received a copy of the GNU General Public License along
> +// with this library; see the file COPYING3.  If not see
> +// <http://www.gnu.org/licenses/>.
> +
> +// { dg-do compile { target c++11 } }
> +
> +#include <type_traits>
> +
> +class Class { Class() {} };
> +
> +template <typename X> static bool foo() {
> +  return std::is_constructible<Class>::value;
> +}
> +
> +static_assert(!std::is_constructible<Class>::value, "");
>
diff mbox series

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 2b393f96e5b..24888f0f712 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7081,42 +7081,6 @@  complain_about_access (tree decl, tree diag_decl, bool issue_error)
     }
 }
 
-/* If the current scope isn't allowed to access DECL along
-   BASETYPE_PATH, give an error.  The most derived class in
-   BASETYPE_PATH is the one used to qualify DECL. DIAG_DECL is
-   the declaration to use in the error diagnostic.  */
-
-bool
-enforce_access (tree basetype_path, tree decl, tree diag_decl,
-		tsubst_flags_t complain, access_failure_info *afi)
-{
-  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
-
-  if (flag_new_inheriting_ctors
-      && DECL_INHERITED_CTOR (decl))
-    {
-      /* 7.3.3/18: The additional constructors are accessible if they would be
-	 accessible when used to construct an object of the corresponding base
-	 class.  */
-      decl = strip_inheriting_ctors (decl);
-      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
-				   ba_any, NULL, complain);
-    }
-
-  if (!accessible_p (basetype_path, decl, true))
-    {
-      if (flag_new_inheriting_ctors)
-	diag_decl = strip_inheriting_ctors (diag_decl);
-      if (complain & tf_error)
-	complain_about_access (decl, diag_decl, true);
-      if (afi)
-	afi->record_access_failure (basetype_path, decl, diag_decl);
-      return false;
-    }
-
-  return true;
-}
-
 /* Initialize a temporary of type TYPE with EXPR.  The FLAGS are a
    bitwise or of LOOKUP_* values.  If any errors are warnings are
    generated, set *DIAGNOSTIC_FN to "error" or "warning",
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 44cb10cfee5..771d51cc283 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6339,9 +6339,6 @@  class access_failure_info
 };
 
 extern void complain_about_access		(tree, tree, bool);
-extern bool enforce_access			(tree, tree, tree,
-						 tsubst_flags_t,
-						 access_failure_info *afi = NULL);
 extern void push_defarg_context			(tree);
 extern void pop_defarg_context			(void);
 extern tree convert_default_arg			(tree, tree, tree, int,
@@ -6939,7 +6936,6 @@  extern tree make_pack_expansion                 (tree, tsubst_flags_t = tf_warni
 extern bool check_for_bare_parameter_packs      (tree, location_t = UNKNOWN_LOCATION);
 extern tree build_template_info			(tree, tree);
 extern tree get_template_info			(const_tree);
-extern vec<qualified_typedef_usage_t, va_gc> *get_types_needing_access_check (tree);
 extern int template_class_depth			(tree);
 extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
@@ -7257,8 +7253,6 @@  extern void finish_mem_initializers		(tree);
 extern tree check_template_template_default_arg (tree);
 extern bool expand_or_defer_fn_1		(tree);
 extern void expand_or_defer_fn			(tree);
-extern void add_typedef_to_current_template_for_access_check (tree, tree,
-							      location_t);
 extern bool check_accessibility_of_qualified_id (tree, tree, tree, tsubst_flags_t);
 extern tree finish_qualified_id_expr		(tree, tree, bool, bool,
 						 bool, bool, tsubst_flags_t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b8bd09b37e6..539609e8ada 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4009,14 +4009,10 @@  make_typename_type (tree context, tree name, enum tag_types tag_type,
       return error_mark_node;
     }
 
-  if (!perform_or_defer_access_check (TYPE_BINFO (context), t, t, complain))
+  if (!check_accessibility_of_qualified_id (t, /*object_type=*/NULL_TREE,
+					    context, complain))
     return error_mark_node;
 
-  /* If we are currently parsing a template and if T is a typedef accessed
-     through CONTEXT then we need to remember and check access of T at
-     template instantiation time.  */
-  add_typedef_to_current_template_for_access_check (t, context, input_location);
-
   if (want_template)
     return lookup_template_class (t, TREE_OPERAND (fullname, 1),
 				  NULL_TREE, context,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b0b31d241f3..ca8e130c790 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -29113,16 +29113,12 @@  cp_parser_template_declaration_after_parameters (cp_parser* parser,
     decl = cp_parser_concept_definition (parser);
   else
     {
-      /* There are no access checks when parsing a template, as we do not
-	 know if a specialization will be a friend.  */
-      push_deferring_access_checks (dk_no_check);
       cp_token *token = cp_lexer_peek_token (parser->lexer);
       decl = cp_parser_single_declaration (parser,
 					   checks,
 					   member_p,
                                            /*explicit_specialization_p=*/false,
 					   &friend_p);
-      pop_deferring_access_checks ();
 
       /* If this is a member template declaration, let the front
 	 end know.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c07a48f1261..be319c50783 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -216,8 +216,6 @@  static bool dependent_type_p_r (tree);
 static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
 static tree tsubst_decl (tree, tree, tsubst_flags_t);
 static void perform_typedefs_access_check (tree tmpl, tree targs);
-static void append_type_to_template_for_access_check_1 (tree, tree, tree,
-							location_t);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
@@ -11522,7 +11520,7 @@  perform_typedefs_access_check (tree tmpl, tree targs)
     return;
 
   if (vec<qualified_typedef_usage_t, va_gc> *tdefs
-      = get_types_needing_access_check (tmpl))
+      = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (get_template_info (tmpl)))
     FOR_EACH_VEC_ELT (*tdefs, i, iter)
       {
 	tree type_decl = iter->typedef_decl;
@@ -11531,8 +11529,10 @@  perform_typedefs_access_check (tree tmpl, tree targs)
 	if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
 	  continue;
 
-	if (uses_template_parms (type_decl))
-	  type_decl = tsubst (type_decl, targs, tf_error, NULL_TREE);
+	if (uses_template_parms (type_decl)
+	    || (TREE_CODE (type_decl) == FIELD_DECL
+		&& uses_template_parms (DECL_CONTEXT (type_decl))))
+	  type_decl = tsubst_copy (type_decl, targs, tf_error, NULL_TREE);
 	if (uses_template_parms (type_scope))
 	  type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
 
@@ -29144,116 +29144,6 @@  check_auto_in_tmpl_args (tree tmpl, tree args)
   return errors;
 }
 
-/* For a given template T, return the vector of typedefs referenced
-   in T for which access check is needed at T instantiation time.
-   T is either  a FUNCTION_DECL or a RECORD_TYPE.
-   Those typedefs were added to T by the function
-   append_type_to_template_for_access_check.  */
-
-vec<qualified_typedef_usage_t, va_gc> *
-get_types_needing_access_check (tree t)
-{
-  gcc_checking_assert ((CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL));
-  
-  if (tree ti = get_template_info (t))
-    if (TI_TEMPLATE (ti))
-      return TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
-
-  return NULL;
-}
-
-/* Append the typedef TYPE_DECL used in template T to a list of typedefs
-   tied to T. That list of typedefs will be access checked at
-   T instantiation time.
-   T is either a FUNCTION_DECL or a RECORD_TYPE.
-   TYPE_DECL is a TYPE_DECL node representing a typedef.
-   SCOPE is the scope through which TYPE_DECL is accessed.
-   LOCATION is the location of the usage point of TYPE_DECL.
-
-   This function is a subroutine of
-   append_type_to_template_for_access_check.  */
-
-static void
-append_type_to_template_for_access_check_1 (tree t,
-					    tree type_decl,
-					    tree scope,
-					    location_t location)
-{
-  qualified_typedef_usage_t typedef_usage;
-  tree ti;
-
-  if (!t || t == error_mark_node)
-    return;
-
-  gcc_assert ((TREE_CODE (t) == FUNCTION_DECL
-	       || CLASS_TYPE_P (t))
-	      && type_decl
-	      && TREE_CODE (type_decl) == TYPE_DECL
-	      && scope);
-
-  if (!(ti = get_template_info (t)))
-    return;
-
-  gcc_assert (TI_TEMPLATE (ti));
-
-  typedef_usage.typedef_decl = type_decl;
-  typedef_usage.context = scope;
-  typedef_usage.locus = location;
-
-  vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), typedef_usage);
-}
-
-/* Append TYPE_DECL to the template TEMPL.
-   TEMPL is either a class type, a FUNCTION_DECL or a TEMPLATE_DECL.
-   At TEMPL instanciation time, TYPE_DECL will be checked to see
-   if it can be accessed through SCOPE.
-   LOCATION is the location of the usage point of TYPE_DECL.
-
-   e.g. consider the following code snippet:
-
-     class C
-     {
-       typedef int myint;
-     };
-
-     template<class U> struct S
-     {
-       C::myint mi; // <-- usage point of the typedef C::myint
-     };
-
-     S<char> s;
-
-   At S<char> instantiation time, we need to check the access of C::myint
-   In other words, we need to check the access of the myint typedef through
-   the C scope. For that purpose, this function will add the myint typedef
-   and the scope C through which its being accessed to a list of typedefs
-   tied to the template S. That list will be walked at template instantiation
-   time and access check performed on each typedefs it contains.
-   Note that this particular code snippet should yield an error because
-   myint is private to C.  */
-
-void
-append_type_to_template_for_access_check (tree templ,
-                                          tree type_decl,
-					  tree scope,
-					  location_t location)
-{
-  qualified_typedef_usage_t *iter;
-  unsigned i;
-
-  gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
-
-  /* Make sure we don't append the type to the template twice.  */
-  if (vec<qualified_typedef_usage_t, va_gc> *tdefs
-      = get_types_needing_access_check (templ))
-    FOR_EACH_VEC_ELT (*tdefs, i, iter)
-      if (iter->typedef_decl == type_decl && scope == iter->context)
-	return;
-
-  append_type_to_template_for_access_check_1 (templ, type_decl,
-					      scope, location);
-}
-
 /* Recursively walk over && expressions searching for EXPR. Return a reference
    to that expression.  */
 
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index b9da2fccb7f..a1a45a5ee6b 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -827,21 +827,6 @@  accessible_p (tree type, tree decl, bool consider_local_p)
   if (current_function_decl && DECL_THUNK_P (current_function_decl))
     return 1;
 
-  /* In a template declaration, we cannot be sure whether the
-     particular specialization that is instantiated will be a friend
-     or not.  Therefore, all access checks are deferred until
-     instantiation.  However, PROCESSING_TEMPLATE_DECL is set in the
-     parameter list for a template (because we may see dependent types
-     in default arguments for template parameters), and access
-     checking should be performed in the outermost parameter list.  */
-  if (processing_template_decl
-      /* FIXME CWG has been talking about doing access checking in the context
-	 of the constraint-expression, rather than the constrained declaration,
-	 in which case we would want to remove this test.  */
-      && !processing_constraint_expression_p ()
-      && (!processing_template_parmlist || processing_template_decl > 1))
-    return 1;
-
   tree otype = NULL_TREE;
   if (!TYPE_P (type))
     {
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 64587c791c6..bf1d720347a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -256,6 +256,68 @@  pop_to_parent_deferring_access_checks (void)
     }
 }
 
+/* If the current scope isn't allowed to access DECL along
+   BASETYPE_PATH, give an error, or if we're parsing a function or class
+   template, defer the access check to be performed at instantiation time.
+   The most derived class in BASETYPE_PATH is the one used to qualify DECL.
+   DIAG_DECL is the declaration to use in the error diagnostic.  */
+
+static bool
+enforce_access (tree basetype_path, tree decl, tree diag_decl,
+		tsubst_flags_t complain, access_failure_info *afi = NULL)
+{
+  gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
+
+  if (flag_new_inheriting_ctors
+      && DECL_INHERITED_CTOR (decl))
+    {
+      /* 7.3.3/18: The additional constructors are accessible if they would be
+	 accessible when used to construct an object of the corresponding base
+	 class.  */
+      decl = strip_inheriting_ctors (decl);
+      basetype_path = lookup_base (basetype_path, DECL_CONTEXT (decl),
+				   ba_any, NULL, complain);
+    }
+
+  tree cs = current_scope ();
+  if (processing_template_decl
+      && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
+    if (tree template_info = get_template_info (cs))
+      {
+	/* When parsing a function or class template, we in general need to
+	   defer access checks until template instantiation time, since a friend
+	   declaration may grant access only to a particular specialization of
+	   the template.  */
+
+	if (accessible_p (basetype_path, decl, /*consider_local_p=*/true))
+	  /* Buf if the member is deemed accessible already, then we can assume
+	     it'll be accessible at instantiation time.  */
+	  return true;
+
+	/* Defer this access check until instantiation time.  */
+	qualified_typedef_usage_t typedef_usage;
+	typedef_usage.typedef_decl = decl;
+	typedef_usage.context = TREE_TYPE (basetype_path);
+	typedef_usage.locus = input_location;
+	vec_safe_push (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (template_info),
+		       typedef_usage);
+	return true;
+      }
+
+  if (!accessible_p (basetype_path, decl, /*consider_local_p=*/true))
+    {
+      if (flag_new_inheriting_ctors)
+	diag_decl = strip_inheriting_ctors (diag_decl);
+      if (complain & tf_error)
+	complain_about_access (decl, diag_decl, true);
+      if (afi)
+	afi->record_access_failure (basetype_path, decl, diag_decl);
+      return false;
+    }
+
+  return true;
+}
+
 /* Perform the access checks in CHECKS.  The TREE_PURPOSE of each node
    is the BINFO indicating the qualifying scope used to access the
    DECL node stored in the TREE_VALUE of the node.  If CHECKS is empty
@@ -320,9 +382,7 @@  perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl,
   deferred_access *ptr;
   deferred_access_check *chk;
 
-
-  /* Exit if we are in a context that no access checking is performed.
-     */
+  /* Exit if we are in a context that no access checking is performed.  */
   if (deferred_access_no_check)
     return true;
 
@@ -1992,37 +2052,6 @@  finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
   return ret;
 }
 
-/* If we are currently parsing a template and we encountered a typedef
-   TYPEDEF_DECL that is being accessed though CONTEXT, this function
-   adds the typedef to a list tied to the current template.
-   At template instantiation time, that list is walked and access check
-   performed for each typedef.
-   LOCATION is the location of the usage point of TYPEDEF_DECL.  */
-
-void
-add_typedef_to_current_template_for_access_check (tree typedef_decl,
-                                                  tree context,
-						  location_t location)
-{
-    tree template_info = NULL;
-    tree cs = current_scope ();
-
-    if (!is_typedef_decl (typedef_decl)
-	|| !context
-	|| !CLASS_TYPE_P (context)
-	|| !cs)
-      return;
-
-    if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)
-      template_info = get_template_info (cs);
-
-    if (template_info
-	&& TI_TEMPLATE (template_info)
-	&& !currently_open_class (context))
-      append_type_to_template_for_access_check (cs, typedef_decl,
-						context, location);
-}
-
 /* DECL was the declaration to which a qualified-id resolved.  Issue
    an error message if it is not accessible.  If OBJECT_TYPE is
    non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
@@ -2039,16 +2068,6 @@  check_accessibility_of_qualified_id (tree decl,
   tree scope;
   tree qualifying_type = NULL_TREE;
 
-  /* If we are parsing a template declaration and if decl is a typedef,
-     add it to a list tied to the template.
-     At template instantiation time, that list will be walked and
-     access check performed.  */
-  add_typedef_to_current_template_for_access_check (decl,
-						    nested_name_specifier
-						    ? nested_name_specifier
-						    : DECL_CONTEXT (decl),
-						    input_location);
-
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
     return true;
@@ -2079,7 +2098,8 @@  check_accessibility_of_qualified_id (tree decl,
 	 current class, treat it as if it were referenced through
 	 `this'.  */
       tree ct;
-      if (DECL_NONSTATIC_MEMBER_P (decl)
+      if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == FIELD_DECL)
+	  && DECL_NONSTATIC_MEMBER_P (decl)
 	  && current_class_ptr
 	  && DERIVED_FROM_P (scope, ct = current_nonlambda_class_type ()))
 	qualifying_type = ct;
@@ -2097,7 +2117,7 @@  check_accessibility_of_qualified_id (tree decl,
       /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
 	 or similar in a default argument value.  */
       && CLASS_TYPE_P (qualifying_type)
-      && !dependent_type_p (qualifying_type))
+      && !dependent_type_p (scope))
     return perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
 					  decl, complain);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
index 206b54a2883..b9a67f5d8da 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
@@ -10,7 +10,7 @@  template <typename b> using g = typename f<b>::e;
 struct b;
 template <typename b> struct f { using e = b; };
 template <typename ai> struct m { typedef g<ai> aj; };
-template <typename b> class n { typedef typename m<b>::aj e; };
+template <typename b> struct n { typedef typename m<b>::aj e; };
 template <typename b> using an = typename n<b>::e;
 template <typename> constexpr bool ao = c<true>::d;
 template <typename> constexpr bool i = c<1>::d;
@@ -38,7 +38,7 @@  template <typename da> concept de = dd<da>;
 struct {
   template <de da, typename b> void operator()(da, b);
 } di;
-class p {
+struct p {
   void begin();
 };
 template <typename> using df = p;
diff --git a/gcc/testsuite/g++.dg/lto/20081219_1.C b/gcc/testsuite/g++.dg/lto/20081219_1.C
index 1bb96ef37de..8d64a0212cb 100644
--- a/gcc/testsuite/g++.dg/lto/20081219_1.C
+++ b/gcc/testsuite/g++.dg/lto/20081219_1.C
@@ -7,7 +7,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
 {
   using::mbstate_t;
   typedef int *__c_locale;
-  class locale
+  struct locale
   {
     class facet;
   };
diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
index 4ddb3854c64..e09ce01cdfc 100644
--- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C
+++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C
@@ -14,7 +14,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
   typedef basic_ostream<char> ostream;
   template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
       class num_get;
-  class locale   {
+  struct locale   {
       class facet;
   };
   class locale::facet   {
diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
index 73686918c2c..4e3de7d6a34 100644
--- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C
+++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
@@ -24,7 +24,9 @@  namespace std
 {
 class locale
 {
+public:
     class facet;
+private:
     class _Impl;
     _Impl *_M_impl;
 };
@@ -70,6 +72,7 @@  class ios_base
     int _M_word_size;
     _Words *_M_word;
     locale _M_ios_locale;
+protected:
     virtual ~ ios_base ();
 };
 template < typename, typename > class istreambuf_iterator
diff --git a/gcc/testsuite/g++.dg/opt/dump1.C b/gcc/testsuite/g++.dg/opt/dump1.C
index 75d71110022..558bee00762 100644
--- a/gcc/testsuite/g++.dg/opt/dump1.C
+++ b/gcc/testsuite/g++.dg/opt/dump1.C
@@ -396,7 +396,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
     ;
   template<typename _Signature>
     class function;
-  class _Function_base
+  struct _Function_base
   {
     template<typename _Functor>
       class _Base_manager
diff --git a/gcc/testsuite/g++.dg/other/pr53574.C b/gcc/testsuite/g++.dg/other/pr53574.C
index cc899a552c8..87622d522ee 100644
--- a/gcc/testsuite/g++.dg/other/pr53574.C
+++ b/gcc/testsuite/g++.dg/other/pr53574.C
@@ -6,7 +6,7 @@  template <typename> struct A { typedef int type; };
 struct B {
   typedef __SIZE_TYPE__ H;
 };
-template <typename> class allocator : B {};
+template <typename> class allocator : public B {};
 template <typename _Alloc> struct C {
   template <typename T>
   static typename T::H foo(T *);
diff --git a/gcc/testsuite/g++.dg/template/access30.C b/gcc/testsuite/g++.dg/template/access30.C
new file mode 100644
index 00000000000..b03a99af1f0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access30.C
@@ -0,0 +1,10 @@ 
+// PR c++/41437
+// { dg-do compile }
+
+class A { struct B { B(); }; };
+template<typename T> void f() { A::B b; } // { dg-error "private" }
+void g() { f<int>(); }
+
+class X { template<typename> struct A{}; };
+
+X::A<int> a; // { dg-error "private" }
diff --git a/gcc/testsuite/g++.dg/template/access31.C b/gcc/testsuite/g++.dg/template/access31.C
new file mode 100644
index 00000000000..0aa7dbbf8f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access31.C
@@ -0,0 +1,29 @@ 
+// PR c++/47346
+// { dg-do compile }
+
+class C
+{
+  struct Private { };
+};
+
+template<typename T>
+struct exploit1
+{
+    typedef C::Private type; // { dg-error "private" }
+};
+exploit1<int>::type x1;
+
+template<typename T>
+struct exploit2 : C::Private // { dg-error "private" }
+{
+};
+exploit2<int> x2;
+
+template<typename T>
+struct exploit3
+{
+    template<class U = C::Private> // { dg-error "private" }
+    struct E {};
+};
+
+exploit3<int>::E<> e;
diff --git a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
index 5072d1ad59d..1f9ad5fdb47 100644
--- a/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
+++ b/gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
@@ -35,7 +35,7 @@  struct __alloc_traits    : allocator_traits<_Alloc>    {
   template<typename _Tp>       struct rebind       {   typedef typename _Base_type::template rebind_alloc<_Tp> other;   };
 };
 
-template<typename _Tp>     class allocator {
+template<typename _Tp>     struct allocator {
   typedef _Tp value_type;
   template<typename _Tp1>  struct rebind  {   typedef allocator<_Tp1> other;   };
 };
diff --git a/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
new file mode 100644
index 00000000000..80646b37f55
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_constructible/94003.cc
@@ -0,0 +1,28 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <type_traits>
+
+class Class { Class() {} };
+
+template <typename X> static bool foo() {
+  return std::is_constructible<Class>::value;
+}
+
+static_assert(!std::is_constructible<Class>::value, "");