From 23cb72663051cd3f5a8952d4aa2186d50243b7d0 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 13 May 2016 15:18:35 -0400 Subject: [PATCH] Fix type-dependence and the current instantiation. PR c++/10200 PR c++/69753 * pt.c (tsubst_decl): Use uses_template_parms. (instantiate_template_1): Handle non-dependent calls in templates. (value_dependent_expression_p): Handle BASELINK, FUNCTION_DECL. (type_dependent_expression_p): Only consider innermost template args. (dependent_template_arg_p): Check enclosing class of a template here. (dependent_template_p): Not here. (type_dependent_object_expression_p): New. * typeck.c (finish_class_member_access_expr): Use it. * parser.c (cp_parser_postfix_expression): Use it. (cp_parser_postfix_dot_deref_expression): Use it. Use comptypes to detect the current instantiation. (cp_parser_lookup_name): Really implement DR 141. * search.c (lookup_field_r): Prefer a dependent using-declaration. (any_dependent_bases_p): Split out from... * name-lookup.c (do_class_using_decl): ...here. * call.c (build_new_method_call_1): Use it. * semantics.c (finish_call_expr): 'this' doesn't make a call dependent. * tree.c (non_static_member_function_p): Remove. * typeck2.c (build_x_arrow): Use dependent_scope_p. From-SVN: r236221 --- gcc/cp/ChangeLog | 22 +++++ gcc/cp/call.c | 3 + gcc/cp/cp-tree.h | 3 +- gcc/cp/name-lookup.c | 13 +-- gcc/cp/parser.c | 35 +++----- gcc/cp/pt.c | 103 +++++++++++++++--------- gcc/cp/search.c | 26 ++++++ gcc/cp/semantics.c | 24 +----- gcc/cp/tree.c | 17 ---- gcc/cp/typeck.c | 23 ++++-- gcc/cp/typeck2.c | 5 +- gcc/testsuite/g++.dg/lookup/member4.C | 17 ++++ gcc/testsuite/g++.dg/lookup/member5.C | 32 ++++++++ gcc/testsuite/g++.dg/template/using14.C | 2 +- 14 files changed, 207 insertions(+), 118 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/member4.C create mode 100644 gcc/testsuite/g++.dg/lookup/member5.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 06ce87f8ba6..025c41274e2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,27 @@ 2016-05-13 Jason Merrill + PR c++/10200 + PR c++/69753 + * pt.c (tsubst_decl): Use uses_template_parms. + (instantiate_template_1): Handle non-dependent calls in templates. + (value_dependent_expression_p): Handle BASELINK, FUNCTION_DECL. + (type_dependent_expression_p): Only consider innermost template args. + (dependent_template_arg_p): Check enclosing class of a template here. + (dependent_template_p): Not here. + (type_dependent_object_expression_p): New. + * typeck.c (finish_class_member_access_expr): Use it. + * parser.c (cp_parser_postfix_expression): Use it. + (cp_parser_postfix_dot_deref_expression): Use it. Use comptypes + to detect the current instantiation. + (cp_parser_lookup_name): Really implement DR 141. + * search.c (lookup_field_r): Prefer a dependent using-declaration. + (any_dependent_bases_p): Split out from... + * name-lookup.c (do_class_using_decl): ...here. + * call.c (build_new_method_call_1): Use it. + * semantics.c (finish_call_expr): 'this' doesn't make a call dependent. + * tree.c (non_static_member_function_p): Remove. + * typeck2.c (build_x_arrow): Use dependent_scope_p. + * parser.c (cp_parser_postfix_dot_deref_expression): Use complete_type_or_else for unknown_type_node, too. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index a49bbb5bdee..0b59c403b31 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8407,6 +8407,9 @@ build_new_method_call_1 (tree instance, tree fns, vec **args, we know we really need it. */ cand->first_arg = instance; } + else if (any_dependent_bases_p ()) + /* We can't tell until instantiation time whether we can use + *this as the implicit object argument. */; else { if (complain & tf_error) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 556c2569d6e..ad21cdf8334 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6125,6 +6125,7 @@ extern bool any_dependent_template_arguments_p (const_tree); extern bool dependent_template_p (tree); extern bool dependent_template_id_p (tree, tree); extern bool type_dependent_expression_p (tree); +extern bool type_dependent_object_expression_p (tree); extern bool any_type_dependent_arguments_p (const vec *); extern bool any_type_dependent_elements_p (const_tree); extern bool type_dependent_expression_p_push (tree); @@ -6233,6 +6234,7 @@ extern tree adjust_result_of_qualified_name_lookup extern tree copied_binfo (tree, tree); extern tree original_binfo (tree, tree); extern int shared_member_p (tree); +extern bool any_dependent_bases_p (tree = current_nonlambda_class_type ()); /* The representation of a deferred access check. */ @@ -6525,7 +6527,6 @@ extern tree get_first_fn (tree); extern tree ovl_cons (tree, tree); extern tree build_overload (tree, tree); extern tree ovl_scope (tree); -extern bool non_static_member_function_p (tree); extern const char *cxx_printable_name (tree, int); extern const char *cxx_printable_name_translate (tree, int); extern tree build_exception_variant (tree, tree); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 86d260c83c1..d32a1532e1a 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3333,8 +3333,6 @@ do_class_using_decl (tree scope, tree name) /* True if any of the bases of CURRENT_CLASS_TYPE are dependent. */ bool bases_dependent_p; tree binfo; - tree base_binfo; - int i; if (name == error_mark_node) return NULL_TREE; @@ -3371,16 +3369,7 @@ do_class_using_decl (tree scope, tree name) || (IDENTIFIER_TYPENAME_P (name) && dependent_type_p (TREE_TYPE (name)))); - bases_dependent_p = false; - if (processing_template_decl) - for (binfo = TYPE_BINFO (current_class_type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); - i++) - if (dependent_type_p (TREE_TYPE (base_binfo))) - { - bases_dependent_p = true; - break; - } + bases_dependent_p = any_dependent_bases_p (); decl = NULL_TREE; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7030740c239..539f1654063 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6851,7 +6851,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, tree fn = TREE_OPERAND (postfix_expression, 1); if (processing_template_decl - && (type_dependent_expression_p (instance) + && (type_dependent_object_expression_p (instance) || (!BASELINK_P (fn) && TREE_CODE (fn) != FIELD_DECL) || type_dependent_expression_p (fn) @@ -7186,8 +7186,9 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, if (token_type == CPP_DEREF) postfix_expression = build_x_arrow (location, postfix_expression, tf_warning_or_error); - /* Check to see whether or not the expression is type-dependent. */ - dependent_p = type_dependent_expression_p (postfix_expression); + /* Check to see whether or not the expression is type-dependent and + not the current instantiation. */ + dependent_p = type_dependent_object_expression_p (postfix_expression); /* The identifier following the `->' or `.' is not qualified. */ parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; @@ -7211,7 +7212,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, required to be of complete type for purposes of class member access (5.2.5) outside the member function body. */ if (postfix_expression != current_class_ref - && !(processing_template_decl && scope == current_class_type)) + && !(processing_template_decl + && current_class_type + && (same_type_ignoring_top_level_qualifiers_p + (scope, current_class_type)))) scope = complete_type_or_else (scope, postfix_expression); /* Let the name lookup machinery know that we are processing a class member access expression. */ @@ -24806,24 +24810,11 @@ cp_parser_lookup_name (cp_parser *parser, tree name, decl = NULL_TREE; if (!decl) - { - /* Look it up in the enclosing context. */ - decl = lookup_name_real (name, tag_type != none_type, - /*nonclass=*/0, - /*block_p=*/true, is_namespace, 0); - /* DR 141 says when looking for a template-name after -> or ., only - consider class templates. We need to fix our handling of - dependent expressions to implement that properly, but for now - let's ignore namespace-scope function templates. */ - if (decl && is_template && !DECL_TYPE_TEMPLATE_P (decl)) - { - tree d = decl; - if (is_overloaded_fn (d)) - d = get_first_fn (d); - if (DECL_P (d) && !DECL_CLASS_SCOPE_P (d)) - decl = NULL_TREE; - } - } + /* Look it up in the enclosing context. DR 141: When looking for a + template-name after -> or ., only consider class templates. */ + decl = lookup_name_real (name, tag_type != none_type || is_template, + /*nonclass=*/0, + /*block_p=*/true, is_namespace, 0); if (object_type == unknown_type_node) /* The object is type-dependent, so we can't look anything up; we used this to get the DR 141 behavior. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1289d64f071..65bfd42a2e7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11700,16 +11700,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL) { tree spec; - bool dependent_p; - /* If T is not dependent, just return it. We have to - increment PROCESSING_TEMPLATE_DECL because - value_dependent_expression_p assumes that nothing is - dependent when PROCESSING_TEMPLATE_DECL is zero. */ - ++processing_template_decl; - dependent_p = value_dependent_expression_p (t); - --processing_template_decl; - if (!dependent_p) + /* If T is not dependent, just return it. */ + if (!uses_template_parms (DECL_TI_ARGS (t))) RETURN (t); /* Calculate the most general template of which R is a @@ -17328,12 +17321,14 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) /* Check to see if we already have this specialization. */ gen_tmpl = most_general_template (tmpl); - if (tmpl != gen_tmpl) - /* The TMPL is a partial instantiation. To get a full set of - arguments we must add the arguments used to perform the - partial instantiation. */ - targ_ptr = add_outermost_template_args (DECL_TI_ARGS (tmpl), - targ_ptr); + if (TMPL_ARGS_DEPTH (targ_ptr) + < TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (gen_tmpl))) + /* targ_ptr only has the innermost template args, so add the outer ones + from tmpl, which could be either a partial instantiation or gen_tmpl (in + the case of a non-dependent call within a template definition). */ + targ_ptr = (add_outermost_template_args + (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (tmpl)), + targ_ptr)); /* It would be nice to avoid hashing here and then again in tsubst_decl, but it doesn't seem to be on the hot path. */ @@ -22653,6 +22648,22 @@ value_dependent_expression_p (tree expression) switch (TREE_CODE (expression)) { + case BASELINK: + /* A member function of a dependent class has dependent template + arguments from its class. */ + if (dependent_type_p (BINFO_TYPE (BASELINK_BINFO (expression)))) + return true; + return value_dependent_expression_p (BASELINK_FUNCTIONS (expression)); + + case FUNCTION_DECL: + /* A function template specialization is value-dependent if it has any + dependent template arguments, since that means it cannot be + instantiated for constexpr evaluation. */ + if (DECL_LANG_SPECIFIC (expression) + && DECL_TEMPLATE_INFO (expression)) + return any_dependent_template_arguments_p (DECL_TI_ARGS (expression)); + break; + case IDENTIFIER_NODE: /* A name that has not been looked up -- must be dependent. */ return true; @@ -22797,10 +22808,10 @@ value_dependent_expression_p (tree expression) case CALL_EXPR: { + if (value_dependent_expression_p (CALL_EXPR_FN (expression))) + return true; tree fn = get_callee_fndecl (expression); int i, nargs; - if (!fn && value_dependent_expression_p (CALL_EXPR_FN (expression))) - return true; nargs = call_expr_nargs (expression); for (i = 0; i < nargs; ++i) { @@ -22964,13 +22975,6 @@ type_dependent_expression_p (tree expression) || dependent_scope_p (scope)); } - /* A function template specialization is type-dependent if it has any - dependent template arguments. */ - if (TREE_CODE (expression) == FUNCTION_DECL - && DECL_LANG_SPECIFIC (expression) - && DECL_TEMPLATE_INFO (expression)) - return any_dependent_template_arguments_p (DECL_TI_ARGS (expression)); - if (TREE_CODE (expression) == TEMPLATE_DECL && !DECL_TEMPLATE_TEMPLATE_PARM_P (expression)) return false; @@ -23023,13 +23027,18 @@ type_dependent_expression_p (tree expression) && DECL_INITIAL (expression)) return true; - /* A variable template specialization is type-dependent if it has any - dependent template arguments. */ - if (VAR_P (expression) + /* A function or variable template-id is type-dependent if it has any + dependent template arguments. Note that we only consider the innermost + template arguments here, since those are the ones that come from the + template-id; the template arguments for the enclosing class do not make it + type-dependent, they only make a member function value-dependent. */ + if (VAR_OR_FUNCTION_DECL_P (expression) && DECL_LANG_SPECIFIC (expression) && DECL_TEMPLATE_INFO (expression) - && variable_template_p (DECL_TI_TEMPLATE (expression))) - return any_dependent_template_arguments_p (DECL_TI_ARGS (expression)); + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (expression)) + && (any_dependent_template_arguments_p + (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression))))) + return true; /* Always dependent, on the number of arguments if nothing else. */ if (TREE_CODE (expression) == EXPR_PACK_EXPANSION) @@ -23087,6 +23096,22 @@ type_dependent_expression_p (tree expression) return (dependent_type_p (TREE_TYPE (expression))); } +/* [temp.dep.expr]/5: A class member access expression (5.2.5) is + type-dependent if the expression refers to a member of the current + instantiation and the type of the referenced member is dependent, or the + class member access expression refers to a member of an unknown + specialization. + + This function returns true if the OBJECT in such a class member access + expression is of an unknown specialization. */ + +bool +type_dependent_object_expression_p (tree object) +{ + tree scope = TREE_TYPE (object); + return (!scope || dependent_scope_p (scope)); +} + /* walk_tree callback function for instantiation_dependent_expression_p, below. Returns non-zero if a dependent subexpression is found. */ @@ -23291,9 +23316,18 @@ dependent_template_arg_p (tree arg) if (TREE_CODE (arg) == ARGUMENT_PACK_SELECT) arg = ARGUMENT_PACK_SELECT_ARG (arg); - if (TREE_CODE (arg) == TEMPLATE_DECL - || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) - return dependent_template_p (arg); + if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) + return true; + if (TREE_CODE (arg) == TEMPLATE_DECL) + { + if (DECL_TEMPLATE_PARM_P (arg)) + return true; + /* A member template of a dependent class is not necessarily + type-dependent, but it is a dependent template argument because it + will be a member of an unknown specialization to that template. */ + tree scope = CP_DECL_CONTEXT (arg); + return TYPE_P (scope) && dependent_type_p (scope); + } else if (ARGUMENT_PACK_P (arg)) { tree args = ARGUMENT_PACK_ARGS (arg); @@ -23389,7 +23423,7 @@ any_dependent_template_arguments_p (const_tree args) return false; } -/* Returns TRUE if the template TMPL is dependent. */ +/* Returns TRUE if the template TMPL is type-dependent. */ bool dependent_template_p (tree tmpl) @@ -23412,9 +23446,6 @@ dependent_template_p (tree tmpl) /* So are names that have not been looked up. */ if (TREE_CODE (tmpl) == SCOPE_REF || identifier_p (tmpl)) return true; - /* So are member templates of dependent classes. */ - if (TYPE_P (CP_DECL_CONTEXT (tmpl))) - return dependent_type_p (DECL_CONTEXT (tmpl)); return false; } diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 503e34b7f2e..f47833f0686 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1106,6 +1106,14 @@ lookup_field_r (tree binfo, void *data) if (!nval) /* Look for a data member or type. */ nval = lookup_field_1 (type, lfi->name, lfi->want_type); + else if (TREE_CODE (nval) == OVERLOAD && OVL_USED (nval)) + { + /* If we have both dependent and non-dependent using-declarations, return + the dependent one rather than an incomplete list of functions. */ + tree dep_using = lookup_field_1 (type, lfi->name, lfi->want_type); + if (dep_using && TREE_CODE (dep_using) == USING_DECL) + nval = dep_using; + } /* If there is no declaration with the indicated name in this type, then there's nothing to do. */ @@ -2844,3 +2852,21 @@ original_binfo (tree binfo, tree here) return result; } +/* True iff TYPE has any dependent bases (and therefore we can't say + definitively that another class is not a base of an instantiation of + TYPE). */ + +bool +any_dependent_bases_p (tree type) +{ + if (!type || !CLASS_TYPE_P (type) || !processing_template_decl) + return false; + + unsigned i; + tree base_binfo; + FOR_EACH_VEC_SAFE_ELT (BINFO_BASE_BINFOS (TYPE_BINFO (type)), i, base_binfo) + if (BINFO_DEPENDENT_BASE_P (base_binfo)) + return true; + + return false; +} diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 817ef995a4c..06dee5a6669 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2300,18 +2300,7 @@ finish_call_expr (tree fn, vec **args, bool disallow_virtual, with no type; type_dependent_expression_p recognizes expressions with no type as being dependent. */ if (type_dependent_expression_p (fn) - || any_type_dependent_arguments_p (*args) - /* For a non-static member function that doesn't have an - explicit object argument, we need to specifically - test the type dependency of the "this" pointer because it - is not included in *ARGS even though it is considered to - be part of the list of arguments. Note that this is - related to CWG issues 515 and 1005. */ - || (TREE_CODE (fn) != COMPONENT_REF - && non_static_member_function_p (fn) - && !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn)) - && current_class_ref - && type_dependent_expression_p (current_class_ref))) + || any_type_dependent_arguments_p (*args)) { result = build_nt_call_vec (fn, *args); SET_EXPR_LOCATION (result, EXPR_LOC_OR_LOC (fn, input_location)); @@ -2399,17 +2388,6 @@ finish_call_expr (tree fn, vec **args, bool disallow_virtual, object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), NULL); - if (processing_template_decl) - { - if (type_dependent_expression_p (object)) - { - tree ret = build_nt_call_vec (orig_fn, orig_args); - release_tree_vector (orig_args); - return ret; - } - object = build_non_dependent_expr (object); - } - result = build_new_method_call (object, fn, args, NULL_TREE, (disallow_virtual ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 57fc5c1c54c..04702ee1c00 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2127,23 +2127,6 @@ ovl_scope (tree ovl) ovl = OVL_CHAIN (ovl); return CP_DECL_CONTEXT (OVL_CURRENT (ovl)); } - -/* Return TRUE if FN is a non-static member function, FALSE otherwise. - This function looks into BASELINK and OVERLOAD nodes. */ - -bool -non_static_member_function_p (tree fn) -{ - if (fn == NULL_TREE) - return false; - - if (is_overloaded_fn (fn)) - fn = get_first_fn (fn); - - return (DECL_P (fn) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)); -} - #define PRINT_RING_SIZE 4 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 0d8a9807bfe..cd058fa258e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2668,7 +2668,7 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, if (processing_template_decl) { if (/* If OBJECT is dependent, so is OBJECT.NAME. */ - type_dependent_expression_p (object) + type_dependent_object_expression_p (object) /* If NAME is "f", where either 'f' or 'args' is dependent, then the expression is dependent. */ || (TREE_CODE (name) == TEMPLATE_ID_EXPR @@ -2678,9 +2678,12 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, expression is dependent. */ || (TREE_CODE (name) == SCOPE_REF && TYPE_P (TREE_OPERAND (name, 0)) - && dependent_type_p (TREE_OPERAND (name, 0)))) - return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF, - object.get_value (), name, NULL_TREE); + && dependent_scope_p (TREE_OPERAND (name, 0)))) + { + dependent: + return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF, + orig_object, name, NULL_TREE); + } object = build_non_dependent_expr (object); } else if (c_dialect_objc () @@ -2805,7 +2808,12 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, } if (TREE_CODE (name) == BIT_NOT_EXPR) - member = lookup_destructor (object, scope, name, complain); + { + if (dependent_type_p (object_type)) + /* The destructor isn't declared yet. */ + goto dependent; + member = lookup_destructor (object, scope, name, complain); + } else { /* Look up the member. */ @@ -2813,6 +2821,9 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, /*want_type=*/false, complain); if (member == NULL_TREE) { + if (dependent_type_p (object_type)) + /* Try again at instantiation time. */ + goto dependent; if (complain & tf_error) { tree guessed_id = lookup_member_fuzzy (access_path, name, @@ -2842,6 +2853,8 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, } if (member == error_mark_node) return error_mark_node; + if (TREE_CODE (member) == USING_DECL && DECL_DEPENDENT_P (member)) + goto dependent; } if (is_template_id) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 1c4e832ff85..833be20f7fe 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1703,7 +1703,10 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain) if (processing_template_decl) { - if (type_dependent_expression_p (expr)) + if (type && TREE_CODE (type) == POINTER_TYPE + && !dependent_scope_p (TREE_TYPE (type))) + /* Pointer to current instantiation, don't treat as dependent. */; + else if (type_dependent_expression_p (expr)) return build_min_nt_loc (loc, ARROW_EXPR, expr); expr = build_non_dependent_expr (expr); } diff --git a/gcc/testsuite/g++.dg/lookup/member4.C b/gcc/testsuite/g++.dg/lookup/member4.C new file mode 100644 index 00000000000..6fab2f9d17b --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/member4.C @@ -0,0 +1,17 @@ +// PR c++/69753 +// { dg-do compile { target c++11 } } + +class A { +public: + template void As(); + static A *FromWebContents(); + A *FromWebContents2(); +}; +template class B : A { + void FromWebContents() { + auto guest = this->A::FromWebContents(); + guest ? guest->As() : nullptr; + auto guest2 = this->A::FromWebContents2(); + guest2 ? guest2->As() : nullptr; + } +}; diff --git a/gcc/testsuite/g++.dg/lookup/member5.C b/gcc/testsuite/g++.dg/lookup/member5.C new file mode 100644 index 00000000000..fec1ecd5bfd --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/member5.C @@ -0,0 +1,32 @@ +// PR c++/69753 +// { dg-do compile { target c++11 } } + +struct B { + template void bfn (); +}; + +template +constexpr int x(T) { return 42; } + +template +struct C +{ + template void cfn (); +}; + +template struct A { + static B fn(int); + template static B ft(U); + + void g() + { + auto b = this->fn(42); + b.bfn(); + + auto b2 = this->ft(42); + b2.bfn(); + + auto c = C(); + c.cfn(); + } +}; diff --git a/gcc/testsuite/g++.dg/template/using14.C b/gcc/testsuite/g++.dg/template/using14.C index 276c40b876c..f1d9799343b 100644 --- a/gcc/testsuite/g++.dg/template/using14.C +++ b/gcc/testsuite/g++.dg/template/using14.C @@ -17,5 +17,5 @@ template struct C : public B1, public B2 int main() { C c; - c.f(); // { dg-message "required" } + c.f(); } -- 2.30.2