c++: Improve access checking inside templates [PR41437]
authorPatrick Palka <ppalka@redhat.com>
Tue, 16 Jun 2020 12:21:33 +0000 (08:21 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 16 Jun 2020 12:21:33 +0000 (08:21 -0400)
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.

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.

17 files changed:
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp2a/concepts-using2.C
gcc/testsuite/g++.dg/lto/20081219_1.C
gcc/testsuite/g++.dg/lto/20091002-1_0.C
gcc/testsuite/g++.dg/lto/pr65475c_0.C
gcc/testsuite/g++.dg/opt/dump1.C
gcc/testsuite/g++.dg/other/pr53574.C
gcc/testsuite/g++.dg/template/access30.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/access31.C [new file with mode: 0644]
gcc/testsuite/g++.dg/wrappers/wrapper-around-type-pack-expansion.C
libstdc++-v3/testsuite/20_util/is_constructible/94003.cc [new file with mode: 0644]

index b99959f76f93d105f3ff424ef152a164aa0ab840..b55dc83f0e7caec48a8add9fe5c8c014a460e8f2 100644 (file)
@@ -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",
index 44cb10cfee5710e99f45f3e0de0fc146c68e999b..771d51cc283c99e09216c6685d77bb94ccb1e6fe 100644 (file)
@@ -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);
index b8bd09b37e686e90686248da84aa613befa75f19..539609e8ada0ed2b14e529fd9e87c8dc7931ba86 100644 (file)
@@ -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,
index bc66e6e5c50815e5259ee4f23894bf67a63a240d..799f310bceee94a13e785e9724704255825cfc70 100644 (file)
@@ -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.  */
index cdf6a3eeaf33f05526f5aa618dbfec439dd7377e..bab48c2fdf608934a8d305c96ee05cf32ee45268 100644 (file)
@@ -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.  */
 
index b9da2fccb7fefebbedf0ed353b20110b62a0ea83..a1a45a5ee6b9ededc995b5b315074e2f0af02da7 100644 (file)
@@ -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))
     {
index 64587c791c67950f1ca85587e9d7575f7068dfc1..13b844a49c9f035dca06336fc75326053f8e28ea 100644 (file)
@@ -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,21 @@ 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);
+  tree scope = context_for_name_lookup (decl);
   /* If the SCOPE is not a type, then DECL is not a member.  */
-  if (!TYPE_P (scope))
+  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 +2118,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);
 
index 206b54a288319f7a38c12f3ce651a1e75fcdb913..b9a67f5d8dae3a297b2050a3f4c920cf579cfb50 100644 (file)
@@ -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;
index 1bb96ef37ded81e9ef72c51d74d17d18289cc51b..8d64a0212cb83e708e6582d94ee7d4a897ee5c7e 100644 (file)
@@ -7,7 +7,7 @@ namespace std __attribute__ ((__visibility__ ("default")))
 {
   using::mbstate_t;
   typedef int *__c_locale;
-  class locale
+  struct locale
   {
     class facet;
   };
index 4ddb3854c64f7db9e3f9265af2fc545572958f29..e09ce01cdfc5d1fc1e24e8802c059ab16302cdde 100644 (file)
@@ -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   {
index 73686918c2cfd09285c10074114077677e76a746..4e3de7d6a349ef2f9b4dfe975f6c86396207be44 100644 (file)
@@ -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
index 75d71110022667a9bf5b78963f24bdcd09bb1f7c..558bee007626943bbf2e8f204cfdee82e6d9a2f8 100644 (file)
@@ -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
index cc899a552c8fae41b173d72f822892b213b35300..87622d522ee5a29281e411e4346b755305ceb511 100644 (file)
@@ -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 (file)
index 0000000..b03a99a
--- /dev/null
@@ -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 (file)
index 0000000..0aa7dbb
--- /dev/null
@@ -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;
index 5072d1ad59d2bc717f63c1fa0062a7e3b915e8b8..1f9ad5fdb4725a2f717c0767f4da6bdbe5398e67 100644 (file)
@@ -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 (file)
index 0000000..80646b3
--- /dev/null
@@ -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, "");