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
> 
> 

Reply via email to