c.opt: Add -fno-deduce-init-list.

* c.opt: Add -fno-deduce-init-list.
    	* pt.c (get_pattern_parm): New.
    	(listify): Split out from...
    	(listify_autos): ...here.
    	(unify): Deduce std::initializer_list for T.
    	* call.c (build_over_call): Warn about it.

From-SVN: r151869
This commit is contained in:
Jason Merrill 2009-09-18 17:53:23 -04:00 committed by Jason Merrill
parent 9e3b62fa8d
commit ab97a3f096
9 changed files with 183 additions and 15 deletions

View File

@ -1,3 +1,7 @@
2009-09-18 Jason Merrill <jason@redhat.com>
* c.opt: Add -fno-deduce-init-list.
2009-09-18 Janis Johnson <janis187@us.ibm.com>
PR c/41049

View File

@ -542,6 +542,10 @@ fconstant-string-class=
ObjC ObjC++ Joined
-fconst-string-class=<name> Use class <name> for constant strings
fdeduce-init-list
C++ ObjC++ Var(flag_deduce_init_list) Init(1)
-fno-deduce-init-list disable deduction of std::initializer_list for a template type parameter from a brace-enclosed initializer-list
fdefault-inline
C++ ObjC++
Inline member functions by default

View File

@ -1,3 +1,11 @@
2009-09-18 Jason Merrill <jason@redhat.com>
* pt.c (get_pattern_parm): New.
(listify): Split out from...
(listify_autos): ...here.
(unify): Deduce std::initializer_list for T.
* call.c (build_over_call): Warn about it.
2009-09-09 Jack Howarth <howarth@bromo.med.uc.edu>
PR bootstrap/41180

View File

@ -5347,6 +5347,34 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
&& !TREE_ADDRESSABLE (type))
conv = conv->u.next;
/* Warn about initializer_list deduction that isn't currently in the
working draft. */
if (cxx_dialect > cxx98
&& flag_deduce_init_list
&& cand->template_decl
&& is_std_init_list (non_reference (type)))
{
tree tmpl = TI_TEMPLATE (cand->template_decl);
tree realparm = DECL_ARGUMENTS (cand->fn);
tree patparm;
int k;
for (k = j; k; --k)
realparm = TREE_CHAIN (realparm);
patparm = get_pattern_parm (realparm, tmpl);
if (!is_std_init_list (non_reference (TREE_TYPE (patparm))))
{
static bool warned = false;
pedwarn (input_location, 0, "deducing %qT as %qT",
non_reference (TREE_TYPE (patparm)),
non_reference (type));
pedwarn (input_location, 0, " in call to %q+D", cand->fn);
pedwarn (input_location, 0,
" (you can disable this with -fno-deduce-init-list)");
}
}
val = convert_like_with_context
(conv, TREE_VALUE (arg), fn, i - is_method, complain);

View File

@ -4584,6 +4584,7 @@ extern tree get_template_info (tree);
extern int template_class_depth (tree);
extern int is_specialization_of (tree, tree);
extern bool is_specialization_of_friend (tree, tree);
extern tree get_pattern_parm (tree, tree);
extern int comp_template_args (tree, tree);
extern tree maybe_process_partial_specialization (tree);
extern tree most_specialized_instantiation (tree);

View File

@ -175,6 +175,8 @@ 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 tree listify (tree);
static tree listify_autos (tree, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
@ -7715,6 +7717,53 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
return result;
}
/* Given PARM_DECL PARM, find the corresponding PARM_DECL in the template
TMPL. We do this using DECL_PARM_INDEX, which should work even with
parameter packs; all parms generated from a function parameter pack will
have the same DECL_PARM_INDEX. */
tree
get_pattern_parm (tree parm, tree tmpl)
{
tree pattern = DECL_TEMPLATE_RESULT (tmpl);
tree patparm;
if (DECL_ARTIFICIAL (parm))
{
for (patparm = DECL_ARGUMENTS (pattern);
patparm; patparm = TREE_CHAIN (patparm))
if (DECL_ARTIFICIAL (patparm)
&& DECL_NAME (parm) == DECL_NAME (patparm))
break;
}
else
{
for (patparm = FUNCTION_FIRST_USER_PARM (pattern);
patparm; patparm = TREE_CHAIN (patparm))
{
if (DECL_NAME (patparm) == DECL_NAME (parm))
break;
if (FUNCTION_PARAMETER_PACK_P (patparm)
/* OK, this is a hack. We know that if PARAM_DECL is expanded
from PACK, its name (built with make_ith_pack_parameter_name)
is the string "<foo>#N" where <foo> is the name of PACK
and N is a number.
So we just check that naming pattern. */
&& (IDENTIFIER_LENGTH (DECL_NAME (patparm))
< IDENTIFIER_LENGTH (DECL_NAME (parm)))
&& ! strncmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
IDENTIFIER_POINTER (DECL_NAME (patparm)),
IDENTIFIER_LENGTH (DECL_NAME (patparm)))
&& (IDENTIFIER_POINTER (DECL_NAME (parm))
[IDENTIFIER_LENGTH (DECL_NAME (patparm))]
== '#'))
break;
}
}
return patparm;
}
/* Substitute ARGS into the vector or list of template arguments T. */
static tree
@ -13320,6 +13369,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
{
tree elt, elttype;
unsigned i;
tree orig_parm = parm;
/* Replace T with std::initializer_list<T> for deduction. */
if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
&& flag_deduce_init_list)
parm = listify (parm);
if (!is_std_init_list (parm))
/* We can only deduce from an initializer list argument if the
@ -13345,6 +13400,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
if (unify (tparms, targs, elttype, elt, elt_strict))
return 1;
}
/* If the std::initializer_list<T> deduction worked, replace the
deduced A with std::initializer_list<A>. */
if (orig_parm != parm)
{
idx = TEMPLATE_TYPE_IDX (orig_parm);
targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
targ = listify (targ);
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ;
}
return 0;
}
@ -16989,26 +17054,33 @@ make_auto (void)
return au;
}
/* Given type ARG, return std::initializer_list<ARG>. */
static tree
listify (tree arg)
{
tree std_init_list = namespace_binding
(get_identifier ("initializer_list"), std_node);
tree argvec;
if (!std_init_list || !DECL_CLASS_TEMPLATE_P (std_init_list))
{
error ("deducing from brace-enclosed initializer list requires "
"#include <initializer_list>");
return error_mark_node;
}
argvec = make_tree_vec (1);
TREE_VEC_ELT (argvec, 0) = arg;
return lookup_template_class (std_init_list, argvec, NULL_TREE,
NULL_TREE, 0, tf_warning_or_error);
}
/* Replace auto in TYPE with std::initializer_list<auto>. */
static tree
listify_autos (tree type, tree auto_node)
{
tree std_init_list = namespace_binding
(get_identifier ("initializer_list"), std_node);
tree argvec;
tree init_auto;
if (!std_init_list || !DECL_CLASS_TEMPLATE_P (std_init_list))
{
error ("deducing auto from brace-enclosed initializer list requires "
"#include <initializer_list>");
return error_mark_node;
}
argvec = make_tree_vec (1);
TREE_VEC_ELT (argvec, 0) = auto_node;
init_auto = lookup_template_class (std_init_list, argvec, NULL_TREE,
NULL_TREE, 0, tf_warning_or_error);
tree init_auto = listify (auto_node);
tree argvec = make_tree_vec (1);
TREE_VEC_ELT (argvec, 0) = init_auto;
if (processing_template_decl)
argvec = add_to_template_args (current_template_args (), argvec);

View File

@ -1734,6 +1734,27 @@ two definitions were merged.
This option is no longer useful on most targets, now that support has
been added for putting variables into BSS without making them common.
@item -fno-deduce-init-list
@opindex fno-deduce-init-list
Disable deduction of a template type parameter as
std::initializer_list from a brace-enclosed initializer list, i.e.
@smallexample
template <class T> auto forward(T t) -> decltype (realfn (t))
@{
return realfn (t);
@}
void f()
@{
forward(@{1,2@}); // call forward<std::initializer_list<int>>
@}
@end smallexample
This option is present because this deduction is an extension to the
current specification in the C++0x working draft, and there was
some concern about potential overload resolution problems.
@item -ffriend-injection
@opindex ffriend-injection
Inject friend functions into the enclosing namespace, so that they are

View File

@ -1,3 +1,7 @@
2009-09-18 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/initlist-deduce.C: New.
2009-09-18 Jack Howarth <howarth@bromo.med.uc.edu>
PR testsuite/41288

View File

@ -0,0 +1,26 @@
// Test for deduction of T as std::initializer_list. This isn't currently
// supported by the working draft, but is necessary for perfect forwarding
// of initializer-lists to things that can take a std::initializer_list.
// { dg-options -std=c++0x }
// { dg-do run }
#include <initializer_list>
struct A
{
A(std::initializer_list<int>) { }
};
void f (A a) { }
template <class T>
auto g (T&& t) -> decltype (f(t)) // { dg-warning "call" }
{
return f(t);
}
int main()
{
g({1}); // { dg-warning "deduc" }
}