From patchwork Wed Aug 17 15:22:33 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 110332 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 70C58B6F90 for ; Thu, 18 Aug 2011 01:23:07 +1000 (EST) Received: (qmail 1721 invoked by alias); 17 Aug 2011 15:23:03 -0000 Received: (qmail 1702 invoked by uid 22791); 17 Aug 2011 15:22:59 -0000 X-SWARE-Spam-Status: No, hits=-6.5 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 17 Aug 2011 15:22:36 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p7HFMZCS018718 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 17 Aug 2011 11:22:35 -0400 Received: from localhost (ovpn-113-111.phx2.redhat.com [10.3.113.111]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p7HFMX6x011696 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 17 Aug 2011 11:22:35 -0400 Received: by localhost (Postfix, from userid 500) id 1F3AB29C094; Wed, 17 Aug 2011 17:22:33 +0200 (CEST) From: Dodji Seketeli To: GCC Patches Cc: Jason Merrill Subject: [PATCH] PR c++/47346 - access control for nested type is ignored in template X-URL: http://www.redhat.com Date: Wed, 17 Aug 2011 17:22:33 +0200 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hello, Consider this code snippet: class C { struct Private { }; }; template struct exploit1 { C::Private type; }; exploit1 x1; //#1 At the instantiation point of exploit1 in #1, the compiler should issue an error because C::Private is private in that context. The infrastructure I have added a while back to do access checking of references to types like this was limited to typedefs only. This bug seems to suggest that the access checking of references to types, at template instantiation should be done for references to all types, not just typedefs. But then, consider this other example: class C { struct Private { }; }; template struct exploit2 : C::Private { }; exploit2 x2; g++ should warn here too, because access to C::Private is private in this context. The problem is when add_typedef_to_current_template_for_access_check is called (from check_accessibility_of_qualified_id), during the parsing of the class header, the "current template" representing exploit2 is not yet created. So the reference to C::Private cannot be added to that not-yet created template. The patch below loosens the existing typedefs access checking mechanisms to make it work for all type references, and defers the scheduling of that access checking when the relevant template is not yet created, until it becomes available. It also adjusts two test cases that were using similar invalid constructs that are now caught by the compiler. Tested on x86_64-unknown-linux-gnu against trunk. gcc/cp/ * cp-tree.h (struct qualified_type_usage_s): Renamed struct qualified_typedef_usage_s into this. (qualified_type_usage_t): Renamed qualified_typedef_usage_t into this. (struct tree_template_info::type_needing_access_checking): Renamed typedefs_needing_access_checking into this. (TI_TYPES_NEEDING_ACCESS_CHECKING): Renamed TI_TYPEDEFS_NEEDING_ACCESS_CHECKING into this. (add_type_decl_to_current_template_for_access_check): Renamed add_typedef_to_current_template_for_access_check into this. (cp_parsing_class_head, cp_no_type_access_check_p): Declare new public global variables. (defer_type_access_check_for_cur_template) (schedule_deferred_access_check_types_for_template): New functions. * semantics.c (add_type_decl_to_current_template_for_access_check): Renamed add_typedef_to_current_template_for_access_check into this. Make it accept potentially accesses to all types, not just typedefs. Make it defer the adding of the type access to the relevant template when said template is not yet available. (check_accessibility_of_qualified_id): Adjust. * decl.c (make_typename_type): Adjust. * parser.c (cp_parsing_class_head, cp_no_type_access_check_p): Define new public global variables. (cp_parser_elaborated_type_specifier): Don't schedule access checks for qualified type names of friend declaration, when in a template context. (cp_parser_class_specifier_1): Schedule qualified type names access check for type names access that happened while parsing the class head of a class template. (cp_parser_class_head): Notify the world when we are parsing a class head. * pt.c (cur_template_deferred_types_to_access_check): Define new global static variable. (perform_types_access_check): Renamed perform_typedefs_access_check into this and adjust the body. (instantiate_class_template_1, get_types_needing_access_check) (append_type_to_template_for_access_check_1) (append_type_to_template_for_access_check): Adjust. (defer_type_access_check_for_cur_template) (schedule_deferred_access_check_types_for_template): Define new functions. gcc/testsuite/ * g++.dg/template/access23.C: New test case. * g++.dg/lto/20081219_1.C: Adjust. * g++.dg/lto/20091002-1_0.C: Likewise. --- gcc/cp/cp-tree.h | 27 +++++---- gcc/cp/decl.c | 4 +- gcc/cp/parser.c | 27 ++++++++- gcc/cp/pt.c | 92 +++++++++++++++++++++++------- gcc/cp/semantics.c | 59 ++++++++++++------- gcc/testsuite/g++.dg/lto/20081219_1.C | 1 + gcc/testsuite/g++.dg/lto/20091002-1_0.C | 1 + gcc/testsuite/g++.dg/template/access23.C | 33 +++++++++++ 8 files changed, 187 insertions(+), 57 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/access23.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ff5509e..3b01573 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -696,18 +696,18 @@ struct GTY (()) tree_lambda_expr In bar, the triplet will be (myint, foo, #1). */ -struct GTY(()) qualified_typedef_usage_s { - tree typedef_decl; +struct GTY(()) qualified_type_usage_s { + tree type_decl; tree context; location_t locus; }; -typedef struct qualified_typedef_usage_s qualified_typedef_usage_t; -DEF_VEC_O (qualified_typedef_usage_t); -DEF_VEC_ALLOC_O (qualified_typedef_usage_t,gc); +typedef struct qualified_type_usage_s qualified_type_usage_t; +DEF_VEC_O (qualified_type_usage_t); +DEF_VEC_ALLOC_O (qualified_type_usage_t,gc); struct GTY(()) tree_template_info { struct tree_common common; - VEC(qualified_typedef_usage_t,gc) *typedefs_needing_access_checking; + VEC(qualified_type_usage_t,gc) *types_needing_access_checking; }; enum cp_tree_node_structure_enum { @@ -2609,9 +2609,9 @@ extern void decl_shadowed_for_var_insert (tree, tree); #endif /* The list of typedefs - used in the template - that need access checking at template instantiation time. */ -#define TI_TYPEDEFS_NEEDING_ACCESS_CHECKING(NODE) \ +#define TI_TYPES_NEEDING_ACCESS_CHECKING(NODE) \ ((struct tree_template_info*)TEMPLATE_INFO_CHECK \ - (NODE))->typedefs_needing_access_checking + (NODE))->types_needing_access_checking /* We use TREE_VECs to hold template arguments. If there is only one level of template arguments, then the TREE_VEC contains the @@ -4093,6 +4093,9 @@ extern int function_depth; sizeof can be nested. */ extern int cp_unevaluated_operand; +extern int cp_parsing_class_head; +extern bool cp_no_type_access_check_p; + extern tree cp_convert_range_for (tree, tree, tree); /* in pt.c */ @@ -5142,6 +5145,8 @@ extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); extern void append_type_to_template_for_access_check (tree, tree, tree, location_t); +extern void defer_type_access_check_for_cur_template (tree, tree, location_t); +extern void schedule_deferred_access_check_types_for_template (tree); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); extern tree process_template_parm (tree, location_t, tree, @@ -5181,7 +5186,7 @@ extern tree make_pack_expansion (tree); extern bool check_for_bare_parameter_packs (tree); extern tree build_template_info (tree, tree); extern tree get_template_info (const_tree); -extern VEC(qualified_typedef_usage_t,gc)* get_types_needing_access_check (tree); +extern VEC(qualified_type_usage_t,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); @@ -5436,8 +5441,8 @@ 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 void add_type_decl_to_current_template_for_access_check (tree, tree, + location_t); extern void check_accessibility_of_qualified_id (tree, tree, tree); extern tree finish_qualified_id_expr (tree, tree, bool, bool, bool, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c125f05..eef727b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3251,10 +3251,10 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, if (complain & tf_error) perform_or_defer_access_check (TYPE_BINFO (context), t, t); - /* If we are currently parsing a template and if T is a typedef accessed + /* If we are currently parsing a template and if T is 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); + add_type_decl_to_current_template_for_access_check (t, context, input_location); if (want_template) return lookup_template_class (t, TREE_OPERAND (fullname, 1), diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 84b8c60..91ab816 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -254,6 +254,9 @@ int cp_unevaluated_operand; /* Dump up to NUM tokens in BUFFER to FILE. If NUM is 0, dump all the tokens. */ +int cp_parsing_class_head = 0; +bool cp_no_type_access_check_p = false; + void cp_lexer_dump_tokens (FILE *file, VEC(cp_token,gc) *buffer, unsigned num) { @@ -13243,7 +13246,14 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, { tree decl; tree ambiguous_decls; - + bool saved_cp_no_type_access_check_p = cp_no_type_access_check_p; + + /* So if we are parsing a friend template declaration, then + we should make sure that looking up the name of the + declaration doesn't schedule it for type access checking + at the time of instantiation of the current containing + template class, if any. */ + cp_no_type_access_check_p = is_friend; decl = cp_parser_lookup_name (parser, identifier, tag_type, /*is_template=*/false, @@ -13251,6 +13261,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, /*check_dependency=*/true, &ambiguous_decls, token->location); + cp_no_type_access_check_p = saved_cp_no_type_access_check_p; /* If the lookup was ambiguous, an error will already have been issued. */ @@ -17071,6 +17082,13 @@ cp_parser_class_specifier_1 (cp_parser* parser) &nested_name_specifier_p, &attributes, &bases); + /* We have parsed the class head, so now we have the resulting TYPE. + If TYPE is a template, then we can stuff if with the type + references that need access checking at its instantiation time. + These access checks were deferred in cp_parser_class_head because + TYPE was not available yet. */ + schedule_deferred_access_check_types_for_template (type); + /* If the class-head was a semantic disaster, skip the entire body of the class. */ if (!type) @@ -17389,13 +17407,17 @@ cp_parser_class_head (cp_parser* parser, type. */ num_templates = 0; parser->colon_corrects_to_scope_p = false; + cp_parsing_class_head++; *bases = NULL_TREE; /* Look for the class-key. */ class_key = cp_parser_class_key (parser); if (class_key == none_type) - return error_mark_node; + { + type = error_mark_node; + goto out; + } /* Parse the attributes. */ attributes = cp_parser_attributes_opt (parser); @@ -17764,6 +17786,7 @@ cp_parser_class_head (cp_parser* parser, if (type && (virt_specifiers & VIRT_SPEC_FINAL)) CLASSTYPE_FINAL (type) = 1; out: + cp_parsing_class_head--; parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; return type; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9ab110a..fb4ab24 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -94,6 +94,10 @@ static GTY ((param_is (spec_entry))) static GTY ((param_is (spec_entry))) htab_t type_specializations; +/* A vector of types that needs to be scheduled for access check when + the current template being parsed becomes available. */ +static GTY (()) VEC(qualified_type_usage_t,gc) *cur_template_deferred_types_to_access_check; + /* Contains canonical template parameter types. The vector is indexed by the TEMPLATE_TYPE_IDX of the template parameter. Each element is a TREE_LIST, whose TREE_VALUEs contain the canonical template @@ -197,7 +201,7 @@ static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool); static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); static tree tsubst_pack_expansion (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 perform_types_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); @@ -8376,18 +8380,18 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, } } -/* Perform (or defer) access check for typedefs that were referenced +/* Perform (or defer) access check for types that were referenced from within the template TMPL code. This is a subroutine of instantiate_template and instantiate_class_template. TMPL is the template to consider and TARGS is the list of arguments of that template. */ static void -perform_typedefs_access_check (tree tmpl, tree targs) +perform_types_access_check (tree tmpl, tree targs) { location_t saved_location; int i; - qualified_typedef_usage_t *iter; + qualified_type_usage_t *iter; if (!tmpl || (!CLASS_TYPE_P (tmpl) @@ -8395,11 +8399,11 @@ perform_typedefs_access_check (tree tmpl, tree targs) return; saved_location = input_location; - FOR_EACH_VEC_ELT (qualified_typedef_usage_t, + FOR_EACH_VEC_ELT (qualified_type_usage_t, get_types_needing_access_check (tmpl), i, iter) { - tree type_decl = iter->typedef_decl; + tree type_decl = iter->type_decl; tree type_scope = iter->context; if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope)) @@ -8905,7 +8909,7 @@ instantiate_class_template_1 (tree type) checked at template instantiation time, i.e now. These types were added to the template at parsing time. Let's get those and perform the access checks then. */ - perform_typedefs_access_check (pattern, args); + perform_types_access_check (pattern, args); perform_deferred_access_checks (); pop_nested_class (); maximum_field_alignment = saved_maximum_field_alignment; @@ -14159,7 +14163,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) checked at template instantiation time, i.e now. These types were added to the template at parsing time. Let's get those and perfom the acces checks then. */ - perform_typedefs_access_check (DECL_TEMPLATE_RESULT (tmpl), targ_ptr); + perform_types_access_check (DECL_TEMPLATE_RESULT (tmpl), targ_ptr); perform_deferred_access_checks (); pop_access_scope (fndecl); pop_deferring_access_checks (); @@ -19912,11 +19916,11 @@ type_uses_auto (tree type) Those typedefs were added to T by the function append_type_to_template_for_access_check. */ -VEC(qualified_typedef_usage_t,gc)* +VEC(qualified_type_usage_t,gc)* get_types_needing_access_check (tree t) { tree ti; - VEC(qualified_typedef_usage_t,gc) *result = NULL; + VEC(qualified_type_usage_t,gc) *result = NULL; if (!t || t == error_mark_node) return NULL; @@ -19930,7 +19934,7 @@ get_types_needing_access_check (tree t) if (!TI_TEMPLATE (ti)) return NULL; - result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti); + result = TI_TYPES_NEEDING_ACCESS_CHECKING (ti); } return result; @@ -19953,7 +19957,7 @@ append_type_to_template_for_access_check_1 (tree t, tree scope, location_t location) { - qualified_typedef_usage_t typedef_usage; + qualified_type_usage_t type_usage; tree ti; if (!t || t == error_mark_node) @@ -19970,13 +19974,13 @@ append_type_to_template_for_access_check_1 (tree t, gcc_assert (TI_TEMPLATE (ti)); - typedef_usage.typedef_decl = type_decl; - typedef_usage.context = scope; - typedef_usage.locus = location; + type_usage.type_decl = type_decl; + type_usage.context = scope; + type_usage.locus = location; - VEC_safe_push (qualified_typedef_usage_t, gc, - TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), - &typedef_usage); + VEC_safe_push (qualified_type_usage_t, gc, + TI_TYPES_NEEDING_ACCESS_CHECKING (ti), + &type_usage); } /* Append TYPE_DECL to the template TEMPL. @@ -20014,16 +20018,16 @@ append_type_to_template_for_access_check (tree templ, tree scope, location_t location) { - qualified_typedef_usage_t *iter; + qualified_type_usage_t *iter; int i; gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL)); /* Make sure we don't append the type to the template twice. */ - FOR_EACH_VEC_ELT (qualified_typedef_usage_t, + FOR_EACH_VEC_ELT (qualified_type_usage_t, get_types_needing_access_check (templ), i, iter) - if (iter->typedef_decl == type_decl && scope == iter->context) + if (iter->type_decl == type_decl && scope == iter->context) return; append_type_to_template_for_access_check_1 (templ, type_decl, @@ -20060,4 +20064,50 @@ print_template_statistics (void) htab_collisions (type_specializations)); } +/* Save the type access check of T through SCOPE, so that it can be + scheduled later when + schedule_deferred_access_check_types_for_template is called. */ + +void +defer_type_access_check_for_cur_template (tree t, tree scope, location_t location) +{ + qualified_type_usage_t type_usage; + + if (t == NULL_TREE || TREE_CODE (t) != TYPE_DECL) + return; + + type_usage.type_decl = t; + type_usage.context = scope; + type_usage.locus = location; + + VEC_safe_push (qualified_type_usage_t, gc, + cur_template_deferred_types_to_access_check, + &type_usage); +} + +/* Add the type access checks stashed away by + defer_type_access_check_for_cur_template to the list of type + access checks to be done at the instantiation time of TEMPL. */ + +void +schedule_deferred_access_check_types_for_template (tree templ) +{ + int i; + qualified_type_usage_t *type_usage; + + FOR_EACH_VEC_ELT (qualified_type_usage_t, + cur_template_deferred_types_to_access_check, + i, type_usage) + append_type_to_template_for_access_check (templ, type_usage->type_decl, + type_usage->context, + type_usage->locus); + + if (cur_template_deferred_types_to_access_check != NULL) + { + VEC_free (qualified_type_usage_t, gc, + cur_template_deferred_types_to_access_check); + cur_template_deferred_types_to_access_check = NULL; + } +} + #include "gt-cp-pt.h" diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 59b25e5..99f5e83 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1606,35 +1606,52 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) } } -/* 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 tempate instantiatin time, that list is walked and access check - performed for each typedef. - LOCATION is the location of the usage point of TYPEDEF_DECL. */ +/* If we are currently parsing a template and we encountered a type + decl DECL that is being accessed though CONTEXT, this function adds + that DECL to a list tied to the current template. At template + instantiatin time, that list is walked and access check performed + for each DECL. + + Note that if we are parsing a class head or a list + of template parameters, there is no "current template" defined yet. + In that case, the function stashes DECL away, until the "current + template" is built and + schedule_deferred_access_check_types_for_template is called. + + LOCATION is the location of the usage point of DECL. */ void -add_typedef_to_current_template_for_access_check (tree typedef_decl, - tree context, - location_t location) +add_type_decl_to_current_template_for_access_check (tree decl, + tree context, + location_t location) { tree template_info = NULL; tree cs = current_scope (); - if (!is_typedef_decl (typedef_decl) + if (decl == NULL_TREE + || TREE_CODE (decl) != TYPE_DECL || !context || !CLASS_TYPE_P (context) - || !cs) + || cp_no_type_access_check_p + || (at_namespace_scope_p () + && !cp_parsing_class_head) + || currently_open_class (context) + || currently_open_class (TREE_TYPE (decl))) return; + if ((cp_parsing_class_head && processing_template_decl) + || processing_template_parmlist) + { + defer_type_access_check_for_cur_template (decl, context, location); + 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); + && TI_TEMPLATE (template_info)) + append_type_to_template_for_access_check (cs, decl, context, location); } /* DECL was the declaration to which a qualified-id resolved. Issue @@ -1651,15 +1668,15 @@ 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, + /* If we are parsing a template declaration and if decl is a TYPE_DECL, 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); + add_type_decl_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) diff --git a/gcc/testsuite/g++.dg/lto/20081219_1.C b/gcc/testsuite/g++.dg/lto/20081219_1.C index 1bb96ef..9e80836 100644 --- a/gcc/testsuite/g++.dg/lto/20081219_1.C +++ b/gcc/testsuite/g++.dg/lto/20081219_1.C @@ -9,6 +9,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) typedef int *__c_locale; class locale { + public: class facet; }; class locale::facet diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C index c63b079..025939d 100644 --- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C +++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C @@ -14,6 +14,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) template > class num_get; class locale { + public: class facet; }; class locale::facet { diff --git a/gcc/testsuite/g++.dg/template/access23.C b/gcc/testsuite/g++.dg/template/access23.C new file mode 100644 index 0000000..b9c9d49 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access23.C @@ -0,0 +1,33 @@ +class C +{ + struct Private { }; // { dg-error "is private" } +}; + +template +struct exploit1 +{ + typedef C::Private type; // { dg-error "in this context" } +}; + +template +struct exploit2 : C::Private // { dg-error "in this context" } +{ +}; + +template +struct exploit3 +{ + C::Private a; // { dg-error "in this context" } +}; + +template +struct exploit4 +{ + template // { dg-error "in this context" } + struct E {}; +}; + +exploit1::type x1; +exploit2 x2; +exploit3 x3; +exploit4::E<> x4;