aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2008-08-30 01:14:54 -0400
committerJason Merrill <jason@gcc.gnu.org>2008-08-30 01:14:54 -0400
commit86a09a9e99fd73423b6b00b1083abfb0d8ac862d (patch)
treee0bd80b1274106f983a05d33d9c48ec65a2d8085
parentb3914aa38f56986ba8ff512ded75608e875436e2 (diff)
downloadgcc-86a09a9e99fd73423b6b00b1083abfb0d8ac862d.zip
gcc-86a09a9e99fd73423b6b00b1083abfb0d8ac862d.tar.gz
gcc-86a09a9e99fd73423b6b00b1083abfb0d8ac862d.tar.bz2
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. From-SVN: r139798
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c18
-rw-r--r--gcc/cp/init.c8
-rw-r--r--gcc/cp/parser.c23
-rw-r--r--gcc/cp/pt.c133
-rw-r--r--gcc/cp/typeck2.c8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto2.C72
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto3.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto4.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto5.C22
11 files changed, 332 insertions, 19 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4318d60..debbaba 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,22 @@
+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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ee1ad6a..72963f0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4521,6 +4521,10 @@ extern void end_specialization (void);
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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c3d63bb..0d4dced 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4203,6 +4203,8 @@ start_decl_1 (tree decl, bool initialized)
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);
@@ -4217,8 +4219,11 @@ start_decl_1 (tree decl, bool initialized)
}
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;
@@ -5406,6 +5411,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
int was_readonly = 0;
bool var_definition_p = false;
int saved_processing_template_decl;
+ tree auto_node;
if (decl == error_mark_node)
return;
@@ -5440,6 +5446,14 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
&& (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;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 34c22fe..1c722f5 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2366,6 +2366,14 @@ build_new (tree placement, tree type, tree nelts, tree init,
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)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 112e2ef..08ec967 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8324,11 +8324,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
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
@@ -8340,10 +8340,9 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
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:
@@ -11069,14 +11068,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
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:
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d5443e6..3b345f1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -16187,6 +16187,19 @@ type_dependent_expression_p (tree expression)
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)
@@ -16673,4 +16686,124 @@ build_non_dependent_args (tree args)
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"
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 9a39076..24d003f 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -398,8 +398,12 @@ cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
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:
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto2.C b/gcc/testsuite/g++.dg/cpp0x/auto2.C
new file mode 100644
index 0000000..a3df9d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto2.C
@@ -0,0 +1,72 @@
+// 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;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto3.C b/gcc/testsuite/g++.dg/cpp0x/auto3.C
new file mode 100644
index 0000000..c16ed7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto3.C
@@ -0,0 +1,16 @@
+// 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" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto4.C b/gcc/testsuite/g++.dg/cpp0x/auto4.C
new file mode 100644
index 0000000..d47bca4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto4.C
@@ -0,0 +1,28 @@
+// 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');
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto5.C b/gcc/testsuite/g++.dg/cpp0x/auto5.C
new file mode 100644
index 0000000..ebe2df2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto5.C
@@ -0,0 +1,22 @@
+// 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>();
+}