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