On Mon, 15 Jun 2020, Jason Merrill wrote: > On 6/5/20 5:16 PM, Patrick Palka wrote: > > The previous patch mostly avoided making any changes that had no > > functional impact, such as adjusting now-outdated comments and > > performing renamings. Such changes have been consolidated to this > > followup patch for easier review. > > > > The main change here is that we now reuse struct deferred_access_check > > as the element type of the vector TI_TYPEDEFS_NEEDING_ACCESS_CHECKING > > (now renamed to TI_DEFERRED_ACCESS_CHECKS, since it now may contain all > > kinds of access checks). > > > > gcc/cp/ChangeLog: > > > > PR c++/41437 > > PR c++/47346 > > * cp-tree.h (qualified_typedef_usage_s): Delete. > > (qualified_typedef_usage_t): Delete. > > (deferred_access_check): Move up in file. > > (tree_template_info::typedefs_needing_access_checking): Delete. > > (tree_template_info::deferred_access_checks): New field. > > (TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): Rename to ... > > (TI_DEFERRED_ACCESS_CHECKS): ... this, and adjust accordingly. > > * pt.c (perform_typedefs_access_check): Rename to ... > > (perform_instantiation_time_access_checks): ... this, and adjust > > accordingly. Remove unnecessary tree tests. > > (instantiate_class_template_1): Adjust accordingly. > > (instantiate_decl): Likewise. > > * semantics.c (enforce_access): Adjust to build up a > > deferred_access_check. > > --- > > gcc/cp/cp-tree.h | 58 +++++++++++++++---------------------------- > > gcc/cp/pt.c | 61 +++++++++++++++++----------------------------- > > gcc/cp/semantics.c | 12 ++++----- > > 3 files changed, 48 insertions(+), 83 deletions(-) > > > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > > index 771d51cc283..50d83add458 100644 > > --- a/gcc/cp/cp-tree.h > > +++ b/gcc/cp/cp-tree.h > > @@ -1449,27 +1449,6 @@ struct GTY (()) tree_lambda_expr > > int discriminator; > > }; > > -/* A (typedef,context,usage location) triplet. > > - It represents a typedef used through a > > - context at a given source location. > > - e.g. > > - struct foo { > > - typedef int myint; > > - }; > > - > > - struct bar { > > - foo::myint v; // #1<-- this location. > > - }; > > - > > - In bar, the triplet will be (myint, foo, #1). > > - */ > > -struct GTY(()) qualified_typedef_usage_s { > > - tree typedef_decl; > > - tree context; > > - location_t locus; > > -}; > > -typedef struct qualified_typedef_usage_s qualified_typedef_usage_t; > > - > > /* Non-zero if this template specialization has access violations that > > should be rechecked when the function is instantiated outside argument > > deduction. */ > > @@ -1489,11 +1468,24 @@ typedef struct qualified_typedef_usage_s > > qualified_typedef_usage_t; > > #define TINFO_VAR_DECLARED_CONSTINIT(NODE) \ > > (TREE_LANG_FLAG_2 (TEMPLATE_INFO_CHECK (NODE))) > > +/* The representation of a deferred access check. */ > > + > > +struct GTY(()) deferred_access_check { > > + /* The base class in which the declaration is referenced. */ > > + tree binfo; > > + /* The declaration whose access must be checked. */ > > + tree decl; > > + /* The declaration that should be used in the error message. */ > > + tree diag_decl; > > + /* The location of this access. */ > > + location_t loc; > > +}; > > + > > struct GTY(()) tree_template_info { > > struct tree_base base; > > tree tmpl; > > tree args; > > - vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking; > > + vec<deferred_access_check, va_gc> *deferred_access_checks; > > }; > > // Constraint information for a C++ declaration. Constraint information > > is > > @@ -3532,14 +3524,15 @@ struct GTY(()) lang_decl { > > ? int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) \ > > : TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (NODE)) > > #endif > > -/* The list of typedefs - used in the template - that need > > - access checking at template instantiation time. > > + > > +/* The list of access checks that were deferred during parsing > > + which need to be performed at template instantiation time. > > FIXME this should be associated with the TEMPLATE_DECL, not the > > TEMPLATE_INFO. */ > > -#define TI_TYPEDEFS_NEEDING_ACCESS_CHECKING(NODE) \ > > +#define TI_DEFERRED_ACCESS_CHECKS(NODE) \ > > ((struct tree_template_info*)TEMPLATE_INFO_CHECK \ > > - (NODE))->typedefs_needing_access_checking > > + (NODE))->deferred_access_checks > > /* We use TREE_VECs to hold template arguments. If there is only one > > level of template arguments, then the TREE_VEC contains the > > @@ -7090,19 +7083,6 @@ extern int shared_member_p > > (tree); > > extern bool any_dependent_bases_p (tree = current_nonlambda_class_type > > ()); > > extern bool maybe_check_overriding_exception_spec (tree, tree); > > -/* The representation of a deferred access check. */ > > - > > -struct GTY(()) deferred_access_check { > > - /* The base class in which the declaration is referenced. */ > > - tree binfo; > > - /* The declaration whose access must be checked. */ > > - tree decl; > > - /* The declaration that should be used in the error message. */ > > - tree diag_decl; > > - /* The location of this access. */ > > - location_t loc; > > -}; > > - > > /* in semantics.c */ > > extern void push_deferring_access_checks (deferring_kind); > > extern void resume_deferring_access_checks (void); > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > > index be319c50783..142392224c6 100644 > > --- a/gcc/cp/pt.c > > +++ b/gcc/cp/pt.c > > @@ -215,7 +215,7 @@ static bool > > any_template_arguments_need_structural_equality_p (tree); > > 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 perform_instantiation_time_access_checks (tree, tree); > > static tree listify (tree); > > static tree listify_autos (tree, tree); > > static tree tsubst_template_parm (tree, tree, tsubst_flags_t); > > @@ -11502,46 +11502,39 @@ apply_late_template_attributes (tree *decl_p, tree > > attributes, int attr_flags, > > } > > } > > -/* Perform (or defer) access check for typedefs that were referenced > > - from within the template TMPL code. > > - This is a subroutine of instantiate_decl and instantiate_class_template. > > - TMPL is the template to consider and TARGS is the list of arguments of > > - that template. */ > > +/* The template TMPL is being instantiated with the template arguments > > TARGS. > > + Perform the access checks that we deferred during parsing of the > > + template. */ > > static void > > -perform_typedefs_access_check (tree tmpl, tree targs) > > +perform_instantiation_time_access_checks (tree tmpl, tree targs) > > { > > unsigned i; > > - qualified_typedef_usage_t *iter; > > + deferred_access_check *chk; > > - if (!tmpl > > - || (!CLASS_TYPE_P (tmpl) > > - && TREE_CODE (tmpl) != FUNCTION_DECL)) > > + if (!CLASS_TYPE_P (tmpl) && TREE_CODE (tmpl) != FUNCTION_DECL) > > return; > > - if (vec<qualified_typedef_usage_t, va_gc> *tdefs > > - = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (get_template_info (tmpl))) > > - FOR_EACH_VEC_ELT (*tdefs, i, iter) > > + if (vec<deferred_access_check, va_gc> *access_checks > > + = TI_DEFERRED_ACCESS_CHECKS (get_template_info (tmpl))) > > + FOR_EACH_VEC_ELT (*access_checks, i, chk) > > { > > - tree type_decl = iter->typedef_decl; > > - tree type_scope = iter->context; > > - > > - if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope)) > > - continue; > > - > > - 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); > > + tree decl = chk->decl; > > + tree diag_decl = chk->diag_decl; > > + tree type_scope = TREE_TYPE (chk->binfo); > > + > > + if (uses_template_parms (decl) > > + || (TREE_CODE (decl) == FIELD_DECL > > + && uses_template_parms (DECL_CONTEXT (decl)))) > > + decl = tsubst_copy (decl, targs, tf_error, NULL_TREE); > > Can decl still be dependent?
Hmm, indeed it looks like not, now that we don't defer accesses of dependently-scoped decls and instead assume that access will be checked during substitution. The following supplemental patch passes 'make check-c++', does the original patch and this one look OK to commit after a full bootstrap and regtest (and smoke testing)? -- >8 -- Subject: [PATCH] c++: TI_DEFERRED_ACCESS_CHECKS and dependent decls This adds an assert to enforce_access to verify that we don't explicitly defer access checks of dependent decls -- we should instead be re-checking the access of such a decl after tsubst'ing into it. gcc/cp/ChangeLog: * pt.c (perform_instantiation_time_access_checks): Don't tsubst into decl. * semantics.c (enforce_access): Verify that decl is not dependent. --- gcc/cp/pt.c | 4 ---- gcc/cp/semantics.c | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 73f5935a4dc..efc69d5f81c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11532,10 +11532,6 @@ perform_instantiation_time_access_checks (tree tmpl, tree targs) tree diag_decl = chk->diag_decl; tree type_scope = TREE_TYPE (chk->binfo); - if (uses_template_parms (decl) - || (TREE_CODE (decl) == FIELD_DECL - && uses_template_parms (DECL_CONTEXT (decl)))) - decl = tsubst_copy (decl, targs, tf_error, NULL_TREE); if (uses_template_parms (type_scope)) type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a04b0aa1d9b..fa059ab6c8e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -294,6 +294,12 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl, assume it'll be accessible at instantiation time. */ return true; + /* Checking access of a dependent decl should be done again after + tsubst'ing into it rather than explicitly deferring here. */ + gcc_assert (!uses_template_parms (decl)); + if (TREE_CODE (decl) == FIELD_DECL) + gcc_assert (!uses_template_parms (DECL_CONTEXT (decl))); + /* Defer this access check until instantiation time. */ deferred_access_check access_check; access_check.binfo = basetype_path; -- 2.27.0.83.g0313f36c6e > > > if (uses_template_parms (type_scope)) > > type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); > > /* Make access check error messages point to the location > > of the use of the typedef. */ > > - iloc_sentinel ils (iter->locus); > > + iloc_sentinel ils (chk->loc); > > perform_or_defer_access_check (TYPE_BINFO (type_scope), > > - type_decl, type_decl, > > - tf_warning_or_error); > > + decl, diag_decl, tf_warning_or_error); > > } > > } > > @@ -12070,11 +12063,7 @@ instantiate_class_template_1 (tree type) > > definitions or default arguments, of the class member functions, > > member classes, static data members and member templates.... */ > > - /* Some typedefs referenced from within the template code need to be > > access > > - 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_instantiation_time_access_checks (pattern, args); > > perform_deferred_access_checks (tf_warning_or_error); > > pop_nested_class (); > > maximum_field_alignment = saved_maximum_field_alignment; > > @@ -25621,12 +25610,8 @@ instantiate_decl (tree d, bool defer_ok, bool > > expl_inst_class_mem_p) > > else > > start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); > > - /* Some typedefs referenced from within the template code need to > > be > > - access 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 (DECL_TEMPLATE_RESULT (td), > > - args); > > + perform_instantiation_time_access_checks (DECL_TEMPLATE_RESULT (td), > > + args); > > /* Create substitution entries for the parameters. */ > > register_parameter_specializations (code_pattern, d); > > diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c > > index bf1d720347a..b94cd88166e 100644 > > --- a/gcc/cp/semantics.c > > +++ b/gcc/cp/semantics.c > > @@ -295,12 +295,12 @@ enforce_access (tree basetype_path, tree decl, tree > > diag_decl, > > 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); > > + deferred_access_check access_check; > > + access_check.binfo = basetype_path; > > + access_check.decl = decl; > > + access_check.diag_decl = diag_decl; > > + access_check.loc = input_location; > > + vec_safe_push (TI_DEFERRED_ACCESS_CHECKS (template_info), > > access_check); > > return true; > > } > > > >