]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Implement C++0x 'auto' semantics.
authorJason Merrill <jason@redhat.com>
Sat, 30 Aug 2008 05:14:54 +0000 (01:14 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 30 Aug 2008 05:14:54 +0000 (01:14 -0400)
        * 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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/auto2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/auto3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/auto4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/auto5.C [new file with mode: 0644]

index 4318d60a788090f9c14aba35e49a65c095784082..debbaba4661655714c68e18adaab68bdd80be8f8 100644 (file)
@@ -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
index ee1ad6ad603885dc1f9b13835d358814b5921631..72963f02cbf7a8d1aba548a639ca50583c55c96e 100644 (file)
@@ -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);
index c3d63bbeaadf2a15fda4f8fd5e94d7111f06b468..0d4dceddf8de78ba78c641a0d1fba47ecf9485d5 100644 (file)
@@ -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;
index 34c22fe039cd1db6951f500e8e3363f96f4c89fc..1c722f52322d6ac0d2f7f2c216495f99afcbd87a 100644 (file)
@@ -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)
index 112e2ef2855c04179b6bc745f74212c3dd0db940..08ec96711c17885c5175b0ce393244b0893cc1a7 100644 (file)
@@ -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:
index d5443e6550572a12cac5bab9cc33f59599bb4a51..3b345f1f4a36930c57bafba2b8292682e1321a0a 100644 (file)
@@ -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"
index 9a39076a0e2395e8eda6e5507685e5a05b365e44..24d003f9afa877f543f39ebfbebe95aa57515627 100644 (file)
@@ -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 (file)
index 0000000..a3df9d1
--- /dev/null
@@ -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 (file)
index 0000000..c16ed7b
--- /dev/null
@@ -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 (file)
index 0000000..d47bca4
--- /dev/null
@@ -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 (file)
index 0000000..ebe2df2
--- /dev/null
@@ -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>();
+}