2016-05-13 Jason Merrill <jason@redhat.com>
+ 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.
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)
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<tree, va_gc> *);
extern bool any_type_dependent_elements_p (const_tree);
extern bool type_dependent_expression_p_push (tree);
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. */
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);
/* 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;
|| (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;
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)
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;
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. */
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. */
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
/* 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. */
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;
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)
{
|| 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;
&& 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)
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. */
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);
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)
/* 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;
}
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. */
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;
+}
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));
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
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));
-}
-
\f
#define PRINT_RING_SIZE 4
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<args>", where either 'f' or 'args' is
dependent, then the expression is dependent. */
|| (TREE_CODE (name) == TEMPLATE_ID_EXPR
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 ()
}
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. */
/*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,
}
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)
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);
}
--- /dev/null
+// PR c++/69753
+// { dg-do compile { target c++11 } }
+
+class A {
+public:
+ template <typename> void As();
+ static A *FromWebContents();
+ A *FromWebContents2();
+};
+template <typename T> class B : A {
+ void FromWebContents() {
+ auto guest = this->A::FromWebContents();
+ guest ? guest->As<T>() : nullptr;
+ auto guest2 = this->A::FromWebContents2();
+ guest2 ? guest2->As<T>() : nullptr;
+ }
+};
--- /dev/null
+// PR c++/69753
+// { dg-do compile { target c++11 } }
+
+struct B {
+ template <class> void bfn ();
+};
+
+template <class T>
+constexpr int x(T) { return 42; }
+
+template <int I>
+struct C
+{
+ template <class> void cfn ();
+};
+
+template <typename T> struct A {
+ static B fn(int);
+ template <class U> static B ft(U);
+
+ void g()
+ {
+ auto b = this->fn(42);
+ b.bfn<int>();
+
+ auto b2 = this->ft(42);
+ b2.bfn<int>();
+
+ auto c = C<x(42)>();
+ c.cfn<int>();
+ }
+};
int main()
{
C<int> c;
- c.f(); // { dg-message "required" }
+ c.f();
}