* decl.c (start_decl_1): Don't complain about auto being incomplete.
(cp_finish_decl): Deduce auto.
* init.c (build_new): Handle 'new auto'.
* typeck2.c (cxx_incomplete_type_diagnostic): Give a different
message for auto than for normal template type parms.
* pt.c (type_dependent_expression_p): Handle { }.
(make_auto): New function.
(listify_autos): New function.
(do_auto_deduction): New function.
(is_auto): New function.
(type_uses_auto): New function.
* cp-tree.h: Declare them.
* parser.c (cp_parser_decl_specifier_seq): In C++0x mode, don't
treat auto as a declspec.
(cp_parser_simple_type_specifier): It's a type-specifier.
From-SVN: r139798
+2008-08-29 Jason Merrill <jason@redhat.com>
+
+ Implement C++0x 'auto' semantics.
+ * decl.c (start_decl_1): Don't complain about auto being incomplete.
+ (cp_finish_decl): Deduce auto.
+ * init.c (build_new): Handle 'new auto'.
+ * typeck2.c (cxx_incomplete_type_diagnostic): Give a different
+ message for auto than for normal template type parms.
+ * pt.c (type_dependent_expression_p): Handle { }.
+ (make_auto): New function.
+ (listify_autos): New function.
+ (do_auto_deduction): New function.
+ (is_auto): New function.
+ (type_uses_auto): New function.
+ * cp-tree.h: Declare them.
+ * parser.c (cp_parser_decl_specifier_seq): In C++0x mode, don't
+ treat auto as a declspec.
+ (cp_parser_simple_type_specifier): It's a type-specifier.
+
2008-08-29 Mark Mitchell <mark@codesourcery.com>
* mangle.c (write_type): Add target-specific manglings for
extern void begin_explicit_instantiation (void);
extern void end_explicit_instantiation (void);
extern tree check_explicit_specialization (tree, tree, int, int);
+extern tree make_auto (void);
+extern tree do_auto_deduction (tree, tree, tree);
+extern tree type_uses_auto (tree);
+extern bool is_auto (const_tree);
extern tree process_template_parm (tree, tree, bool, bool);
extern tree end_template_parm_list (tree);
extern void end_template_decl (void);
arrays which might be completed by the initialization. */
if (complete_p)
; /* A complete type is ok. */
+ else if (type_uses_auto (type))
+ ; /* An auto type is ok. */
else if (TREE_CODE (type) != ARRAY_TYPE)
{
error ("variable %q#D has initializer but incomplete type", decl);
}
else if (aggregate_definition_p && !complete_p)
{
- error ("aggregate %q#D has incomplete type and cannot be defined",
- decl);
+ if (type_uses_auto (type))
+ error ("declaration of %q#D has no initializer", decl);
+ else
+ error ("aggregate %q#D has incomplete type and cannot be defined",
+ decl);
/* Change the type so that assemble_variable will give
DECL an rtl we can live with: (mem (const_int 0)). */
type = TREE_TYPE (decl) = error_mark_node;
int was_readonly = 0;
bool var_definition_p = false;
int saved_processing_template_decl;
+ tree auto_node;
if (decl == error_mark_node)
return;
&& (DECL_INITIAL (decl) || init))
DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
+ auto_node = type_uses_auto (type);
+ if (auto_node && !type_dependent_expression_p (init))
+ {
+ type = TREE_TYPE (decl) = do_auto_deduction (type, init, auto_node);
+ if (type == error_mark_node)
+ return;
+ }
+
if (processing_template_decl)
{
bool type_dependent_p;
orig_nelts = nelts;
orig_init = init;
+ if (nelts == NULL_TREE && init != void_zero_node && list_length (init) == 1
+ && !any_type_dependent_arguments_p (init))
+ {
+ tree auto_node = type_uses_auto (type);
+ if (auto_node)
+ type = do_auto_deduction (type, TREE_VALUE (init), auto_node);
+ }
+
if (processing_template_decl)
{
if (dependent_type_p (type)
GNU Extension:
thread */
case RID_AUTO:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
-
if (cxx_dialect == cxx98)
{
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+
/* Complain about `auto' as a storage specifier, if
we're complaining about C++0x compatibility. */
warning
cp_parser_set_storage_class (parser, decl_specs, RID_AUTO,
token->location);
}
- else
- /* We do not yet support the use of `auto' as a
- type-specifier. */
- error ("%HC++0x %<auto%> specifier not supported", &token->location);
+ else
+ /* C++0x auto type-specifier. */
+ found_decl_spec = false;
break;
case RID_REGISTER:
break;
case RID_AUTO:
- if (cxx_dialect != cxx98)
- {
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- /* We do not yet support the use of `auto' as a
- type-specifier. */
- error ("%HC++0x %<auto%> specifier not supported", &token->location);
- }
+ maybe_warn_cpp0x ("C++0x auto");
+ type = make_auto ();
break;
case RID_DECLTYPE:
if (TREE_CODE (expression) == STMT_EXPR)
expression = stmt_expr_value_expr (expression);
+ if (BRACE_ENCLOSED_INITIALIZER_P (expression))
+ {
+ tree elt;
+ unsigned i;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expression), i, elt)
+ {
+ if (type_dependent_expression_p (elt))
+ return true;
+ }
+ return false;
+ }
+
if (TREE_TYPE (expression) == unknown_type_node)
{
if (TREE_CODE (expression) == ADDR_EXPR)
return nreverse (new_args);
}
+/* Returns a type which represents 'auto'. We use a TEMPLATE_TYPE_PARM
+ with a level one deeper than the actual template parms. */
+
+tree
+make_auto (void)
+{
+ tree au;
+
+ /* ??? Is it worth caching this for multiple autos at the same level? */
+ au = cxx_make_type (TEMPLATE_TYPE_PARM);
+ TYPE_NAME (au) = build_decl (TYPE_DECL, get_identifier ("auto"), au);
+ TYPE_STUB_DECL (au) = TYPE_NAME (au);
+ TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
+ (0, processing_template_decl + 1, processing_template_decl + 1,
+ TYPE_NAME (au), NULL_TREE);
+ TYPE_CANONICAL (au) = canonical_type_parameter (au);
+ DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
+ SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au));
+
+ return au;
+}
+
+/* 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_VEC_ELT (argvec, 0) = init_auto;
+ if (processing_template_decl)
+ argvec = add_to_template_args (current_template_args (), argvec);
+ return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
+}
+
+/* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
+ from INIT. AUTO_NODE is the TEMPLATE_TYPE_PARM used for 'auto' in TYPE. */
+
+tree
+do_auto_deduction (tree type, tree init, tree auto_node)
+{
+ tree parms, args, tparms, targs;
+ int val;
+
+ /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto
+ with either a new invented type template parameter U or, if the
+ initializer is a braced-init-list (8.5.4), with
+ std::initializer_list<U>. */
+ if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ type = listify_autos (type, auto_node);
+
+ parms = build_tree_list (NULL_TREE, type);
+ args = build_tree_list (NULL_TREE, init);
+ tparms = make_tree_vec (1);
+ targs = make_tree_vec (1);
+ TREE_VEC_ELT (tparms, 0)
+ = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
+ val = type_unification_real (tparms, targs, parms, args, 0,
+ DEDUCE_CALL, LOOKUP_NORMAL);
+ if (val > 0)
+ {
+ error ("unable to deduce %qT from %qE", type, init);
+ return error_mark_node;
+ }
+
+ if (processing_template_decl)
+ targs = add_to_template_args (current_template_args (), targs);
+ return tsubst (type, targs, tf_warning_or_error, NULL_TREE);
+}
+
+/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto'. */
+
+bool
+is_auto (const_tree type)
+{
+ if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ && TYPE_IDENTIFIER (type) == get_identifier ("auto"))
+ return true;
+ else
+ return false;
+}
+
+/* Returns true iff TYPE contains a use of 'auto'. Since auto can only
+ appear as a type-specifier for the declaration in question, we don't
+ have to look through the whole type. */
+
+tree
+type_uses_auto (tree type)
+{
+ enum tree_code code;
+ if (is_auto (type))
+ return type;
+
+ code = TREE_CODE (type);
+
+ if (code == POINTER_TYPE || code == REFERENCE_TYPE
+ || code == OFFSET_TYPE || code == FUNCTION_TYPE
+ || code == METHOD_TYPE || code == ARRAY_TYPE)
+ return type_uses_auto (TREE_TYPE (type));
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ return type_uses_auto (TREE_TYPE (TREE_TYPE
+ (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+
+ return NULL_TREE;
+}
+
#include "gt-cp-pt.h"
break;
case TEMPLATE_TYPE_PARM:
- emit_diagnostic (diag_kind, input_location, 0,
- "invalid use of template type parameter %qT", type);
+ if (is_auto (type))
+ emit_diagnostic (diag_kind, input_location, 0,
+ "invalid use of %<auto%>");
+ else
+ emit_diagnostic (diag_kind, input_location, 0,
+ "invalid use of template type parameter %qT", type);
break;
case BOUND_TEMPLATE_TEMPLATE_PARM:
--- /dev/null
+// Positive test for auto
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <typeinfo>
+extern "C" void abort();
+
+int f() {}
+
+struct A
+{
+ int i;
+ int f() {}
+ A operator+(A a) { return a; }
+};
+
+template <class T>
+void g(T t)
+{
+ auto x = t+t;
+ if (typeid(x) != typeid(t+t))
+ abort();
+
+ auto p = new auto(&t);
+ if (typeid(p) != typeid(T**))
+ abort();
+}
+
+int main()
+{
+ auto i = 42;
+ if (typeid (i) != typeid (int))
+ abort();
+
+ auto *p = &i;
+ if (typeid (p) != typeid (int*))
+ abort();
+
+ auto *p2 = &p;
+ if (typeid (p2) != typeid (int**))
+ abort();
+
+ auto (*fp)() = f;
+ if (typeid (fp) != typeid (int (*)()))
+ abort();
+
+ auto A::* pm = &A::i;
+ if (typeid (pm) != typeid (int A::*))
+ abort();
+
+ auto (A::*pmf)() = &A::f;
+ if (typeid (pmf) != typeid (int (A::*)()))
+ abort();
+
+ g(42);
+ g(10.f);
+ g(A());
+
+ auto *p3 = new auto (i);
+ if (typeid (p3) != typeid (int*))
+ abort();
+
+ for (auto idx = i; idx != 0; idx = 0);
+ while (auto idx = 0);
+ if (auto idx = 1);
+
+ switch (auto s = i)
+ {
+ case 42:
+ break;
+ }
+}
--- /dev/null
+// Negative test for auto
+// { dg-options "-std=c++0x" }
+
+#include <initializer_list>
+
+auto x; // { dg-error "auto" }
+
+// New CWG issue
+auto a[2] = { 1, 2 }; // { dg-error "auto" }
+
+template<class T>
+struct A { };
+
+A<int> A1;
+// CWG issue 625
+A<auto> A2 = A1; // { dg-error "auto" }
--- /dev/null
+// Testcase for deduction of std::initializer_list for auto.
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+#include <typeinfo>
+#include <initializer_list>
+extern "C" void abort();
+
+template <class T>
+void f (T t)
+{
+ auto ilt = { &t, &t };
+ if (typeid(ilt) != typeid(std::initializer_list<T*>))
+ abort();
+
+ auto il = { 1, 2, 3 };
+ if (typeid(il) != typeid(std::initializer_list<int>))
+ abort();
+}
+
+int main()
+{
+ auto il = { 1, 2, 3 };
+ if (typeid(il) != typeid(std::initializer_list<int>))
+ abort();
+
+ f('c');
+}
--- /dev/null
+// Testcase for non-dependent auto in templates
+// { dg-options "-std=c++0x" }
+
+struct A
+{
+ template<class> void f();
+} a;
+
+template <class T>
+void g()
+{
+ auto aa = a;
+ aa.f<int>();
+
+ auto p = new auto (a);
+ p->f<int>();
+}
+
+int main()
+{
+ g<double>();
+}