diff options
author | Jason Merrill <jason@redhat.com> | 2008-08-30 01:14:54 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2008-08-30 01:14:54 -0400 |
commit | 86a09a9e99fd73423b6b00b1083abfb0d8ac862d (patch) | |
tree | e0bd80b1274106f983a05d33d9c48ec65a2d8085 /gcc | |
parent | b3914aa38f56986ba8ff512ded75608e875436e2 (diff) | |
download | gcc-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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 4 | ||||
-rw-r--r-- | gcc/cp/decl.c | 18 | ||||
-rw-r--r-- | gcc/cp/init.c | 8 | ||||
-rw-r--r-- | gcc/cp/parser.c | 23 | ||||
-rw-r--r-- | gcc/cp/pt.c | 133 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/auto2.C | 72 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/auto3.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/auto4.C | 28 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/auto5.C | 22 |
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>(); +} |