From 34da880074f38f11309e262bdfdc10cd1c197957 Mon Sep 17 00:00:00 2001 From: dgregor Date: Fri, 27 Jul 2007 17:43:05 +0000 Subject: [PATCH] 2007-07-27 Douglas Gregor * typeck.c (structural_comptypes): Compare DECLTYPE_TYPE nodes. * cp-tree.def (DECLTYPE_TYPE): New. * error.c (dump_type): Dump DECLTYPE_TYPE nodes. (dump_type_prefix): Ditto. (dump_type_suffix): Ditto. * tree.c (DECLTYPE_TYPE): Walk DECLTYPE_TYPE nodes. * mangle.c (write_type): Handle DECLTYPE_TYPE. * cp-tree.h (IS_AGGR_TYPE): DECLTYPE_TYPE nodes can be aggregate types. (DECLTYPE_TYPE_EXPR): New. (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P): New. (finish_declared_type): Declare. * cxx-pretty-print.c (pp_cxx_type_specifier_seq): Print DECLTYPE_TYPE nodes. (pp_cxx_type_id): Ditto. * pt.c (for_each_template_parm_r): Walk DECLTYPE_TYPE children. (tsubst): Substitute into a DECLTYPE_TYPE node. (tsubst_copy): Ditto. (unify): Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE nodes. (dependent_type_p_r): DECLTYPE_TYPE types are always dependent. * semantics.c (finish_typeof): TYPEOF_TYPE types need to use structural equality (because we can't hash the expressions). (finish_declared_type): New. * lex.c (reswords): Add "decltype" keyword. * parser.c cp_lexer_next_token_is_decl_specifier_keyword (cp_parser_postfix_expression): Add member_access_only_p to restrict postfix expression to member access expressions. (cp_parser_unary_expression): Update call to cp_parser_postfix_expression to reflect new parameter. (cp_parser_declared_type): New. (cp_parser_simple_type_specifier): Parse decltype types. 2007-07-27 Douglas Gregor * c-common.h (enum rid): Add RID_DECLTYPE, update RID_LAST_CXX0X. 2007-07-27 Douglas Gregor * g++.dg/cpp0x/decltype1.C: New. * g++.dg/cpp0x/decltype2.C: New. * g++.dg/cpp0x/decltype3.C: New. * g++.dg/cpp0x/decltype4.C: New. * g++.dg/cpp0x/decltype5.C: New. * g++.dg/cpp0x/decltype6.C: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126991 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 4 + gcc/c-common.h | 4 +- gcc/cp/ChangeLog | 35 ++++++ gcc/cp/cp-tree.def | 7 ++ gcc/cp/cp-tree.h | 11 ++ gcc/cp/cxx-pretty-print.c | 8 ++ gcc/cp/error.c | 10 ++ gcc/cp/lex.c | 2 + gcc/cp/mangle.c | 13 +++ gcc/cp/parser.c | 201 ++++++++++++++++++++++++++++++++- gcc/cp/pt.c | 32 +++++- gcc/cp/semantics.c | 164 +++++++++++++++++++++++++++ gcc/cp/tree.c | 6 + gcc/cp/typeck.c | 8 ++ gcc/testsuite/ChangeLog | 9 ++ gcc/testsuite/g++.dg/cpp0x/decltype1.C | 28 +++++ gcc/testsuite/g++.dg/cpp0x/decltype2.C | 59 ++++++++++ gcc/testsuite/g++.dg/cpp0x/decltype3.C | 72 ++++++++++++ gcc/testsuite/g++.dg/cpp0x/decltype4.C | 82 ++++++++++++++ gcc/testsuite/g++.dg/cpp0x/decltype5.C | 38 +++++++ gcc/testsuite/g++.dg/cpp0x/decltype6.C | 36 ++++++ 21 files changed, 819 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype5.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype6.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a13f349..283c343 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2007-07-27 Douglas Gregor + + * c-common.h (enum rid): Add RID_DECLTYPE, update RID_LAST_CXX0X. + 2007-07-26 Kenneth Zadeck PR middle-end/32749 diff --git a/gcc/c-common.h b/gcc/c-common.h index 5417c8b..cb2c56b 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -101,7 +101,7 @@ enum rid RID_IS_UNION, /* C++0x */ - RID_STATIC_ASSERT, + RID_STATIC_ASSERT, RID_DECLTYPE, /* Objective-C */ RID_AT_ENCODE, RID_AT_END, @@ -119,7 +119,7 @@ enum rid RID_LAST_MODIFIER = RID_ONEWAY, RID_FIRST_CXX0X = RID_STATIC_ASSERT, - RID_LAST_CXX0X = RID_STATIC_ASSERT, + RID_LAST_CXX0X = RID_DECLTYPE, RID_FIRST_AT = RID_AT_ENCODE, RID_LAST_AT = RID_AT_IMPLEMENTATION, RID_FIRST_PQ = RID_IN, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3c7b8c6..5141298 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +2007-07-27 Douglas Gregor + + * typeck.c (structural_comptypes): Compare DECLTYPE_TYPE nodes. + * cp-tree.def (DECLTYPE_TYPE): New. + * error.c (dump_type): Dump DECLTYPE_TYPE nodes. + (dump_type_prefix): Ditto. + (dump_type_suffix): Ditto. + * tree.c (DECLTYPE_TYPE): Walk DECLTYPE_TYPE nodes. + * mangle.c (write_type): Handle DECLTYPE_TYPE. + * cp-tree.h (IS_AGGR_TYPE): DECLTYPE_TYPE nodes can be aggregate + types. + (DECLTYPE_TYPE_EXPR): New. + (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P): New. + (finish_declared_type): Declare. + * cxx-pretty-print.c (pp_cxx_type_specifier_seq): Print + DECLTYPE_TYPE nodes. + (pp_cxx_type_id): Ditto. + * pt.c (for_each_template_parm_r): Walk DECLTYPE_TYPE children. + (tsubst): Substitute into a DECLTYPE_TYPE node. + (tsubst_copy): Ditto. + (unify): Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE + nodes. + (dependent_type_p_r): DECLTYPE_TYPE types are always dependent. + * semantics.c (finish_typeof): TYPEOF_TYPE types need to use + structural equality (because we can't hash the expressions). + (finish_declared_type): New. + * lex.c (reswords): Add "decltype" keyword. + * parser.c cp_lexer_next_token_is_decl_specifier_keyword + (cp_parser_postfix_expression): Add member_access_only_p to + restrict postfix expression to member access expressions. + (cp_parser_unary_expression): Update call to + cp_parser_postfix_expression to reflect new parameter. + (cp_parser_declared_type): New. + (cp_parser_simple_type_specifier): Parse decltype types. + 2007-07-27 Mark Mitchell PR c++/32346 diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index a0feb30..3dd6646 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -427,6 +427,13 @@ DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0) /* Represents a trait expression during template expansion. */ DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0) +/* The declared type of an expression. This is a C++0x extension. + DECLTYPE_TYPE_EXPR is the expression whose type we are computing. + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P states whether the + expression was parsed as an id-expression or a member access + expression. When false, it was parsed as a full expression. */ +DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e440171..52cd6ae 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -977,6 +977,7 @@ enum languages { lang_c, lang_cplusplus, lang_java }; || TREE_CODE (T) == TYPENAME_TYPE \ || TREE_CODE (T) == TYPEOF_TYPE \ || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \ + || TREE_CODE (T) == DECLTYPE_TYPE \ || TYPE_LANG_FLAG_5 (T)) /* Set IS_AGGR_TYPE for T to VAL. T must be a class, struct, or @@ -2921,6 +2922,15 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* The expression in question for a TYPEOF_TYPE. */ #define TYPEOF_TYPE_EXPR(NODE) (TYPEOF_TYPE_CHECK (NODE))->type.values +/* The expression in question for a DECLTYPE_TYPE. */ +#define DECLTYPE_TYPE_EXPR(NODE) (DECLTYPE_TYPE_CHECK (NODE))->type.values + +/* Whether the DECLTYPE_TYPE_EXPR of NODE was originally parsed as an + id-expression or a member-access expression. When false, it was + parsed as a full expression. */ +#define DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P(NODE) \ + (DECLTYPE_TYPE_CHECK (NODE))->type.string_flag + /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was specified in its declaration. This can also be set for an erroneously declared PARM_DECL. */ @@ -4657,6 +4667,7 @@ extern bool cxx_omp_privatize_by_reference (tree); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool); +extern tree finish_decltype_type (tree, bool); extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); /* in tree.c */ diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index ac75e1d..9717969 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -1198,6 +1198,13 @@ pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t) pp_cxx_nested_name_specifier (pp, TYPE_METHOD_BASETYPE (t)); break; + case DECLTYPE_TYPE: + pp_cxx_identifier (pp, "decltype"); + pp_cxx_left_paren (pp); + pp_cxx_expression (pp, DECLTYPE_TYPE_EXPR (t)); + pp_cxx_right_paren (pp); + break; + default: if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t))) pp_c_specifier_qualifier_list (pp_c_base (pp), t); @@ -1581,6 +1588,7 @@ pp_cxx_type_id (cxx_pretty_printer *pp, tree t) case TEMPLATE_PARM_INDEX: case TEMPLATE_DECL: case TYPEOF_TYPE: + case DECLTYPE_TYPE: case TEMPLATE_ID_EXPR: pp_cxx_type_specifier_seq (pp, t); break; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 7e4828c..7df9256 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -408,6 +408,14 @@ dump_type (tree t, int flags) } break; + case DECLTYPE_TYPE: + pp_cxx_identifier (cxx_pp, "decltype"); + pp_cxx_whitespace (cxx_pp); + pp_cxx_left_paren (cxx_pp); + dump_expr (DECLTYPE_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS); + pp_cxx_right_paren (cxx_pp); + break; + default: pp_unsupported_tree (cxx_pp, t); /* Fall through to error. */ @@ -611,6 +619,7 @@ dump_type_prefix (tree t, int flags) case COMPLEX_TYPE: case VECTOR_TYPE: case TYPEOF_TYPE: + case DECLTYPE_TYPE: dump_type (t, flags); pp_base (cxx_pp)->padding = pp_before; break; @@ -707,6 +716,7 @@ dump_type_suffix (tree t, int flags) case COMPLEX_TYPE: case VECTOR_TYPE: case TYPEOF_TYPE: + case DECLTYPE_TYPE: break; default: diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index f1dc864..6aefb47 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -197,6 +197,7 @@ static const struct resword reswords[] = { "__complex__", RID_COMPLEX, 0 }, { "__const", RID_CONST, 0 }, { "__const__", RID_CONST, 0 }, + { "__decltype", RID_DECLTYPE, 0 }, { "__extension__", RID_EXTENSION, 0 }, { "__func__", RID_C99_FUNCTION_NAME, 0 }, { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, 0 }, @@ -244,6 +245,7 @@ static const struct resword reswords[] = { "const", RID_CONST, 0 }, { "const_cast", RID_CONSTCAST, 0 }, { "continue", RID_CONTINUE, 0 }, + { "decltype", RID_DECLTYPE, D_CXX0X }, { "default", RID_DEFAULT, 0 }, { "delete", RID_DELETE, 0 }, { "do", RID_DO, 0 }, diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index d708a2b..7318f49 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1544,6 +1544,9 @@ write_local_name (const tree function, const tree local_entity, C++0x extensions ::= RR # rvalue reference-to + ::= Dt # decltype of an id-expression or + # class member access + ::= DT # decltype of an expression TYPE is a type node. */ @@ -1674,6 +1677,16 @@ write_type (tree type) write_type (PACK_EXPANSION_PATTERN (type)); break; + case DECLTYPE_TYPE: + write_char ('D'); + if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)) + write_char ('t'); + else + write_char ('T'); + write_expression (DECLTYPE_TYPE_EXPR (type)); + write_char ('E'); + break; + default: gcc_unreachable (); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b8d2b15..a7190cb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -577,6 +577,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer) /* GNU extensions. */ case RID_ATTRIBUTE: case RID_TYPEOF: + /* C++0x extensions. */ + case RID_DECLTYPE: return true; default: @@ -1582,7 +1584,7 @@ static tree cp_parser_nested_name_specifier static tree cp_parser_class_or_namespace_name (cp_parser *, bool, bool, bool, bool, bool); static tree cp_parser_postfix_expression - (cp_parser *, bool, bool); + (cp_parser *, bool, bool, bool); static tree cp_parser_postfix_open_square_expression (cp_parser *, tree, bool); static tree cp_parser_postfix_dot_deref_expression @@ -1707,6 +1709,8 @@ static void cp_parser_linkage_specification (cp_parser *); static void cp_parser_static_assert (cp_parser *, bool); +static tree cp_parser_decltype + (cp_parser *); /* Declarators [gram.dcl.decl] */ @@ -4254,15 +4258,20 @@ cp_parser_class_or_namespace_name (cp_parser *parser, `&' operator. CAST_P is true if this expression is the target of a cast. + If MEMBER_ACCESS_ONLY_P, we only allow postfix expressions that are + class member access expressions [expr.ref]. + Returns a representation of the expression. */ static tree -cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) +cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, + bool member_access_only_p) { cp_token *token; enum rid keyword; cp_id_kind idk = CP_ID_KIND_NONE; tree postfix_expression = NULL_TREE; + bool is_member_access = false; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -4513,6 +4522,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) postfix_expression, false); idk = CP_ID_KIND_NONE; + is_member_access = false; break; case CPP_OPEN_PAREN: @@ -4524,6 +4534,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) bool saved_non_integral_constant_expression_p = false; tree args; + is_member_access = false; + is_builtin_constant_p = DECL_IS_BUILTIN_CONSTANT_P (postfix_expression); if (is_builtin_constant_p) @@ -4669,6 +4681,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) = cp_parser_postfix_dot_deref_expression (parser, token->type, postfix_expression, false, &idk); + + is_member_access = true; break; case CPP_PLUS_PLUS: @@ -4684,6 +4698,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) "an increment")) postfix_expression = error_mark_node; idk = CP_ID_KIND_NONE; + is_member_access = false; break; case CPP_MINUS_MINUS: @@ -4699,10 +4714,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) "a decrement")) postfix_expression = error_mark_node; idk = CP_ID_KIND_NONE; + is_member_access = false; break; default: - return postfix_expression; + if (member_access_only_p) + return is_member_access? postfix_expression : error_mark_node; + else + return postfix_expression; } } @@ -5341,7 +5360,8 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p) return expression; } - return cp_parser_postfix_expression (parser, address_p, cast_p); + return cp_parser_postfix_expression (parser, address_p, cast_p, + /*member_access_only_p=*/false); } /* Returns ERROR_MARK if TOKEN is not a unary-operator. If TOKEN is a @@ -8371,6 +8391,164 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) finish_static_assert (condition, message, saved_loc, member_p); } +/* Parse a `decltype' type. Returns the type. + + simple-type-specifier: + decltype ( expression ) */ + +static tree +cp_parser_decltype (cp_parser *parser) +{ + tree expr; + bool id_expression_or_member_access_p = false; + const char *saved_message; + bool saved_integral_constant_expression_p; + bool saved_non_integral_constant_expression_p; + + /* Look for the `decltype' token. */ + if (!cp_parser_require_keyword (parser, RID_DECLTYPE, "`decltype'")) + return error_mark_node; + + /* Types cannot be defined in a `decltype' expression. Save away the + old message. */ + saved_message = parser->type_definition_forbidden_message; + + /* And create the new one. */ + parser->type_definition_forbidden_message + = "types may not be defined in `decltype' expressions"; + + /* The restrictions on constant-expressions do not apply inside + decltype expressions. */ + saved_integral_constant_expression_p + = parser->integral_constant_expression_p; + saved_non_integral_constant_expression_p + = parser->non_integral_constant_expression_p; + parser->integral_constant_expression_p = false; + + /* Do not actually evaluate the expression. */ + ++skip_evaluation; + + /* Parse the opening `('. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + + /* First, try parsing an id-expression. */ + cp_parser_parse_tentatively (parser); + expr = cp_parser_id_expression (parser, + /*template_keyword_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + + if (!cp_parser_error_occurred (parser) && expr != error_mark_node) + { + bool non_integral_constant_expression_p = false; + tree id_expression = expr; + cp_id_kind idk; + const char *error_msg; + + /* Lookup the name we got back from the id-expression. */ + expr = cp_parser_lookup_name (parser, expr, + none_type, + /*is_template=*/false, + /*is_namespace=*/false, + /*check_dependency=*/true, + /*ambiguous_decls=*/NULL); + + if (expr + && expr != error_mark_node + && TREE_CODE (expr) != TEMPLATE_ID_EXPR + && TREE_CODE (expr) != TYPE_DECL + && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) + { + /* Complete lookup of the id-expression. */ + expr = (finish_id_expression + (id_expression, expr, parser->scope, &idk, + /*integral_constant_expression_p=*/false, + /*allow_non_integral_constant_expression_p=*/true, + &non_integral_constant_expression_p, + /*template_p=*/false, + /*done=*/true, + /*address_p=*/false, + /*template_arg_p=*/false, + &error_msg)); + + if (expr == error_mark_node) + /* We found an id-expression, but it was something that we + should not have found. This is an error, not something + we can recover from, so note that we found an + id-expression and we'll recover as gracefully as + possible. */ + id_expression_or_member_access_p = true; + } + + if (expr + && expr != error_mark_node + && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) + /* We have an id-expression. */ + id_expression_or_member_access_p = true; + } + + if (!id_expression_or_member_access_p) + { + /* Abort the id-expression parse. */ + cp_parser_abort_tentative_parse (parser); + + /* Parsing tentatively, again. */ + cp_parser_parse_tentatively (parser); + + /* Parse a class member access. */ + expr = cp_parser_postfix_expression (parser, /*address_p=*/false, + /*cast_p=*/false, + /*member_access_only_p=*/true); + + if (expr + && expr != error_mark_node + && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) + /* We have an id-expression. */ + id_expression_or_member_access_p = true; + } + + if (id_expression_or_member_access_p) + /* We have parsed the complete id-expression or member access. */ + cp_parser_parse_definitely (parser); + else + { + /* Abort our attempt to parse an id-expression or member access + expression. */ + cp_parser_abort_tentative_parse (parser); + + /* Parse a full expression. */ + expr = cp_parser_expression (parser, /*cast_p=*/false); + } + + /* Go back to evaluating expressions. */ + --skip_evaluation; + + /* Restore the old message and the integral constant expression + flags. */ + parser->type_definition_forbidden_message = saved_message; + parser->integral_constant_expression_p + = saved_integral_constant_expression_p; + parser->non_integral_constant_expression_p + = saved_non_integral_constant_expression_p; + + if (expr == error_mark_node) + { + /* Skip everything up to the closing `)'. */ + cp_parser_skip_to_closing_parenthesis (parser, true, false, + /*consume_paren=*/true); + return error_mark_node; + } + + /* Parse to the closing `)'. */ + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, true, false, + /*consume_paren=*/true); + + return finish_decltype_type (expr, id_expression_or_member_access_p); +} + /* Special member functions [gram.special] */ /* Parse a conversion-function-id. @@ -10438,6 +10616,11 @@ cp_parser_type_specifier (cp_parser* parser, double void + C++0x Extension: + + simple-type-specifier: + decltype ( expression ) + GNU Extension: simple-type-specifier: @@ -10507,6 +10690,16 @@ cp_parser_simple_type_specifier (cp_parser* parser, type = void_type_node; break; + case RID_DECLTYPE: + /* Parse the `decltype' type. */ + type = cp_parser_decltype (parser); + + if (decl_specs) + cp_parser_set_decl_spec_type (decl_specs, type, + /*user_defined_p=*/true); + + return type; + case RID_TYPEOF: /* Consume the `typeof' token. */ cp_lexer_consume_token (parser->lexer); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index fc5af16..d05bfd2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9058,6 +9058,22 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) complain); } + case DECLTYPE_TYPE: + { + tree type; + + type = + finish_decltype_type (tsubst_expr + (DECLTYPE_TYPE_EXPR (t), args, + complain, in_decl, + /*integral_constant_expression_p=*/false), + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t)); + return cp_build_qualified_type_real (type, + cp_type_quals (t) + | cp_type_quals (type), + complain); + } + case TYPE_ARGUMENT_PACK: case NONTYPE_ARGUMENT_PACK: { @@ -9621,6 +9637,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) case TYPENAME_TYPE: case UNBOUND_CLASS_TEMPLATE: case TYPEOF_TYPE: + case DECLTYPE_TYPE: case TYPE_DECL: return tsubst (t, args, complain, in_decl); @@ -12824,6 +12841,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) break; + case TYPEOF_TYPE: + case DECLTYPE_TYPE: + /* Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_TYPE + nodes. */ + return 0; + default: gcc_assert (EXPR_P (parm)); @@ -14888,10 +14911,11 @@ dependent_type_p_r (tree type) (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type))))) return true; - /* All TYPEOF_TYPEs are dependent; if the argument of the `typeof' - expression is not type-dependent, then it should already been - have resolved. */ - if (TREE_CODE (type) == TYPEOF_TYPE) + /* All TYPEOF_TYPEs and DECLTYPE_TYPEs are dependent; if the + argument of the `typeof' expression is not type-dependent, then + it should already been have resolved. */ + if (TREE_CODE (type) == TYPEOF_TYPE + || TREE_CODE (type) == DECLTYPE_TYPE) return true; /* A template argument pack is dependent if any of its packed diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6b0d407..b03ec2f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2935,6 +2935,7 @@ finish_typeof (tree expr) { type = make_aggr_type (TYPEOF_TYPE); TYPEOF_TYPE_EXPR (type) = expr; + SET_TYPE_STRUCTURAL_EQUALITY (type); return type; } @@ -4036,6 +4037,169 @@ finish_static_assert (tree condition, tree message, location_t location, input_location = saved_loc; } } + +/* Implements the C++0x decltype keyword. Returns the type of EXPR, + suitable for use as a type-specifier. + + ID_EXPRESSION_OR_MEMBER_ACCESS_P is true when EXPR was parsed as an + id-expression or a class member access, FALSE when it was parsed as + a full expression. */ +tree +finish_decltype_type (tree expr, bool id_expression_or_member_access_p) +{ + tree orig_expr = expr; + tree type; + + if (type_dependent_expression_p (expr)) + { + type = make_aggr_type (DECLTYPE_TYPE); + DECLTYPE_TYPE_EXPR (type) = expr; + DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type) + = id_expression_or_member_access_p; + SET_TYPE_STRUCTURAL_EQUALITY (type); + + return type; + } + + /* The type denoted by decltype(e) is defined as follows: */ + + if (id_expression_or_member_access_p) + { + /* If e is an id-expression or a class member access (5.2.5 + [expr.ref]), decltype(e) is defined as the type of the entity + named by e. If there is no such entity, or e names a set of + overloaded functions, the program is ill-formed. */ + if (TREE_CODE (expr) == IDENTIFIER_NODE) + expr = lookup_name (expr); + + if (TREE_CODE (expr) == INDIRECT_REF) + /* This can happen when the expression is, e.g., "a.b". Just + look at the underlying operand. */ + expr = TREE_OPERAND (expr, 0); + + if (TREE_CODE (expr) == OFFSET_REF + || TREE_CODE (expr) == MEMBER_REF) + /* We're only interested in the field itself. If it is a + BASELINK, we will need to see through it in the next + step. */ + expr = TREE_OPERAND (expr, 1); + + if (TREE_CODE (expr) == BASELINK) + /* See through BASELINK nodes to the underlying functions. */ + expr = BASELINK_FUNCTIONS (expr); + + if (TREE_CODE (expr) == OVERLOAD) + { + if (OVL_CHAIN (expr)) + { + error ("%qE refers to a set of overloaded functions", orig_expr); + return error_mark_node; + } + else + /* An overload set containing only one function: just look + at that function. */ + expr = OVL_FUNCTION (expr); + } + + switch (TREE_CODE (expr)) + { + case FIELD_DECL: + if (DECL_C_BIT_FIELD (expr)) + { + type = DECL_BIT_FIELD_TYPE (expr); + break; + } + /* Fall through for fields that aren't bitfields. */ + + case FUNCTION_DECL: + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + type = TREE_TYPE (expr); + break; + + case ERROR_MARK: + type = error_mark_node; + break; + + case COMPONENT_REF: + type = is_bitfield_expr_with_lowered_type (expr); + if (!type) + type = TREE_TYPE (TREE_OPERAND (expr, 1)); + break; + + case BIT_FIELD_REF: + gcc_unreachable (); + + case INTEGER_CST: + /* We can get here when the id-expression refers to an + enumerator. */ + type = TREE_TYPE (expr); + break; + + default: + gcc_assert (TYPE_P (expr) || DECL_P (expr)); + error ("argument to decltype must be an expression"); + return error_mark_node; + } + } + else + { + tree fndecl; + + if (TREE_CODE (expr) == CALL_EXPR + && (fndecl = get_callee_fndecl (expr)) + && (fndecl != error_mark_node)) + /* If e is a function call (5.2.2 [expr.call]) or an + invocation of an overloaded operator (parentheses around e + are ignored), decltype(e) is defined as the return type of + that function. */ + type = TREE_TYPE (TREE_TYPE (fndecl)); + else + { + type = is_bitfield_expr_with_lowered_type (expr); + if (type) + { + /* Bitfields are special, because their type encodes the + number of bits they store. If the expression referenced a + bitfield, TYPE now has the declared type of that + bitfield. */ + type = cp_build_qualified_type (type, + cp_type_quals (TREE_TYPE (expr))); + + if (real_lvalue_p (expr)) + type = build_reference_type (type); + } + else + { + /* Otherwise, where T is the type of e, if e is an lvalue, + decltype(e) is defined as T&, otherwise decltype(e) is + defined as T. */ + type = TREE_TYPE (expr); + if (expr == current_class_ptr) + /* If the expression is just "this", we want the + cv-unqualified pointer for the "this" type. */ + type = TYPE_MAIN_VARIANT (type); + else if (real_lvalue_p (expr)) + { + if (TREE_CODE (type) != REFERENCE_TYPE) + type = build_reference_type (type); + } + else + type = non_reference (type); + } + } + } + + if (!type || type == unknown_type_node) + { + error ("type of %qE is unknown", expr); + return error_mark_node; + } + + return type; +} /* Called from trait_expr_value to evaluate either __has_nothrow_assign or __has_nothrow_copy, depending on assign_p. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 772df4c..9757363 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2380,6 +2380,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, *walk_subtrees_p = 0; break; + case DECLTYPE_TYPE: + WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp)); + *walk_subtrees_p = 0; + break; + + default: return NULL_TREE; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 51deeb2..65371c7 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1080,6 +1080,14 @@ structural_comptypes (tree t1, tree t2, int strict) return same_type_p (PACK_EXPANSION_PATTERN (t1), PACK_EXPANSION_PATTERN (t2)); + case DECLTYPE_TYPE: + if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) + != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2) + || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), + DECLTYPE_TYPE_EXPR (t2))) + return false; + break; + default: return false; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9b75942..c37bd1d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2007-07-27 Douglas Gregor + + * g++.dg/cpp0x/decltype1.C: New. + * g++.dg/cpp0x/decltype2.C: New. + * g++.dg/cpp0x/decltype3.C: New. + * g++.dg/cpp0x/decltype4.C: New. + * g++.dg/cpp0x/decltype5.C: New. + * g++.dg/cpp0x/decltype6.C: New. + 2007-07-27 Rask Ingemann Lambertsen * gcc.dg/torture/pr27743.c (bar): Use an integer of exactly 32 bits diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype1.C b/gcc/testsuite/g++.dg/cpp0x/decltype1.C new file mode 100644 index 0000000..447af54 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype1.C @@ -0,0 +1,28 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +const int& foo(); +int i; +struct A { double x; }; +const A* a = new A(); + +static_assert(is_same::value, + "type should be const int&"); +static_assert(is_same::value, + "type should be int"); +static_assert(is_samex), double>::value, + "type should be double"); +static_assert(is_samex)), const double&>::value, + "type should be const double&"); diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype2.C b/gcc/testsuite/g++.dg/cpp0x/decltype2.C new file mode 100644 index 0000000..65549b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype2.C @@ -0,0 +1,59 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +#define CHECK_DECLTYPE(DECLTYPE,RESULT) \ + static_assert(is_same< DECLTYPE , RESULT >::value, #RESULT) + +struct A {}; + +int a; +int& b = a; +const int& c = a; +const int d = 5; +const A e = A(); +CHECK_DECLTYPE(decltype(a), int); +CHECK_DECLTYPE(decltype(b), int&); +CHECK_DECLTYPE(decltype(c), const int&); +CHECK_DECLTYPE(decltype(d), const int); +CHECK_DECLTYPE(decltype(e), const A); + +CHECK_DECLTYPE(decltype(a), int); +CHECK_DECLTYPE(decltype((a)), int&); + +void foo_check(int a, int& b, float& c, int* d) +{ + CHECK_DECLTYPE(decltype(a), int); + CHECK_DECLTYPE(decltype(b), int&); + CHECK_DECLTYPE(decltype(c), float&); + CHECK_DECLTYPE(decltype(d), int*); +} + +int foo(char); +int bar(char); +int bar(int); +CHECK_DECLTYPE(decltype(foo), int(char)); + +decltype(bar) z; // { dg-error "overload" } +// { dg-error "invalid type" "" { target *-*-* } 48 } + +CHECK_DECLTYPE(decltype(&foo), int(*)(char)); +CHECK_DECLTYPE(decltype(*&foo), int(&)(char)); + +void array_types() +{ + int a[10]; + CHECK_DECLTYPE(decltype(a), int[10]); +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype3.C b/gcc/testsuite/g++.dg/cpp0x/decltype3.C new file mode 100644 index 0000000..556ae70 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype3.C @@ -0,0 +1,72 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +#define CHECK_DECLTYPE(DECLTYPE,RESULT) \ + static_assert(is_same< DECLTYPE , RESULT >::value, #DECLTYPE " should be " #RESULT) + +class A { +public: + int a; + int& b; + static int c; + + A(int& b) : b(b) { } + + void foo() { + CHECK_DECLTYPE(decltype(a), int); + CHECK_DECLTYPE(decltype(this->a), int); + CHECK_DECLTYPE(decltype((*this).a), int); + CHECK_DECLTYPE(decltype(b), int&); + CHECK_DECLTYPE(decltype(c), int); + } + void bar() const { + CHECK_DECLTYPE(decltype(a), int); + CHECK_DECLTYPE(decltype(b), int&); + CHECK_DECLTYPE(decltype(c), int); + } +}; + +int b; +A aa(b); +const A& caa = aa; +CHECK_DECLTYPE(decltype(aa.a), int); +CHECK_DECLTYPE(decltype(aa.b), int&); +CHECK_DECLTYPE(decltype(caa.a), int); + +class B { +public: + int a; // { dg-error "invalid use" } + enum B_enum { b }; + decltype(a) c; // { dg-error "from this location" } + decltype(a) foo() { } // { dg-error "from this location" } + decltype(b) enums_are_in_scope() { return b; } // ok +}; + +CHECK_DECLTYPE(decltype(aa.*&A::a), int&); +decltype(aa.*&A::b) zz; // { dg-error "cannot create pointer to reference member" } +// { dg-error "invalid type" "" { target *-*-* } 58 } +CHECK_DECLTYPE(decltype(caa.*&A::a), const int&); + +class X { + void foo() { + CHECK_DECLTYPE(decltype(this), X*); + CHECK_DECLTYPE(decltype(*this), X&); + } + void bar() const { + CHECK_DECLTYPE(decltype(this), const X*); + CHECK_DECLTYPE(decltype(*this), const X&); + } +}; + diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype4.C b/gcc/testsuite/g++.dg/cpp0x/decltype4.C new file mode 100644 index 0000000..18f2734 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype4.C @@ -0,0 +1,82 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +#define CHECK_DECLTYPE(DECLTYPE,RESULT) \ + static_assert(is_same< DECLTYPE , RESULT >::value, #DECLTYPE " should be " #RESULT) + +struct A { + int x; + int& y; + int foo(char); + int& bar() const; +}; + +CHECK_DECLTYPE(decltype(&A::x), int A::*); +decltype(&A::y) Ay; // { dg-error "cannot create pointer to reference member|invalid type" } +CHECK_DECLTYPE(decltype(&A::foo), int (A::*) (char)); +CHECK_DECLTYPE(decltype(&A::bar), int& (A::*) () const); + +CHECK_DECLTYPE(decltype("decltype"), const char(&)[9]); +CHECK_DECLTYPE(decltype(1), int); + +int an_int = 5; +int& i = an_int; +const int j = an_int; + +CHECK_DECLTYPE(decltype(i)&, int&); +CHECK_DECLTYPE(const decltype(j), const int); + +int foo(); +CHECK_DECLTYPE(decltype(foo()), int); +float& bar(int); +CHECK_DECLTYPE(decltype (bar(1)), float&); +const A bar(); +CHECK_DECLTYPE(decltype (bar()), const A); +const A& bar2(); +CHECK_DECLTYPE(decltype (bar2()), const A&); + +void wibble() { + CHECK_DECLTYPE(decltype(1+2), int); + int* p; + CHECK_DECLTYPE(decltype(*p), int&); + int a[10]; + CHECK_DECLTYPE(decltype(a[3]), int&); + int i; int& j = i; + CHECK_DECLTYPE(decltype (i = 5), int&); + CHECK_DECLTYPE(decltype (j = 5), int&); + + CHECK_DECLTYPE(decltype (++i), int&); + CHECK_DECLTYPE(decltype (i++), int); +} + +struct B { + int bit : 2; + const int cbit : 3; + + void foo() + { + CHECK_DECLTYPE(decltype(bit), int); + CHECK_DECLTYPE(decltype((bit)), int&); + CHECK_DECLTYPE(decltype(cbit), const int); + CHECK_DECLTYPE(decltype((cbit)), const int&); // { dg-bogus "static assertion failed" "GCC gets the actual type of this expression wrong" { xfail *-*-* } 73 } + } +}; + +B b; +const B& bc = b; +CHECK_DECLTYPE(decltype(b.bit), int); +CHECK_DECLTYPE(decltype(bc.bit), int); +CHECK_DECLTYPE(decltype((b.bit)), int&); +CHECK_DECLTYPE(decltype((bc.bit)), const int&); diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype5.C b/gcc/testsuite/g++.dg/cpp0x/decltype5.C new file mode 100644 index 0000000..4e8e64b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype5.C @@ -0,0 +1,38 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +#define CHECK_DECLTYPE(DECLTYPE,RESULT) \ + static_assert(is_same< DECLTYPE , RESULT >::value, #RESULT) + +template F create_a(); + +template +decltype(create_a()(create_a())) forward(F f, const T1& a1) +{ + return f(a1); +} + +struct identity { + template + const T& operator()(const T& x) { return x; } +}; + + +identity id; +int i; +float f; + +CHECK_DECLTYPE(decltype(forward(id, i)), const int&); +CHECK_DECLTYPE(decltype(forward(id, f)), const float&); diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype6.C b/gcc/testsuite/g++.dg/cpp0x/decltype6.C new file mode 100644 index 0000000..c407c18 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype6.C @@ -0,0 +1,36 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +template const T& foo(); + + +int i; + +template +struct A +{ + double x; +}; + +const A* a = new A(); + +static_assert(is_same()), const int&>::value, + "type should be const int&"); +static_assert(is_same::value, + "type should be int"); +static_assert(is_samex), double>::value, + "type should be double"); +static_assert(is_samex)), const double&>::value, + "type should be const double&"); -- 2.7.4