summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
authordgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>2007-07-27 17:43:05 +0000
committerdgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>2007-07-27 17:43:05 +0000
commit34da880074f38f11309e262bdfdc10cd1c197957 (patch)
tree1fd8c965b4122258e1d88e04db3ecb09a3757908 /gcc
parentd598b5d86b330d16ef1f2181f4bc52f2b01ab283 (diff)
downloadppe42-gcc-34da880074f38f11309e262bdfdc10cd1c197957.tar.gz
ppe42-gcc-34da880074f38f11309e262bdfdc10cd1c197957.zip
2007-07-27 Douglas Gregor <doug.gregor@gmail.com>
* 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 <doug.gregor@gmail.com> * c-common.h (enum rid): Add RID_DECLTYPE, update RID_LAST_CXX0X. 2007-07-27 Douglas Gregor <doug.gregor@gmail.com> * 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/c-common.h4
-rw-r--r--gcc/cp/ChangeLog35
-rw-r--r--gcc/cp/cp-tree.def7
-rw-r--r--gcc/cp/cp-tree.h11
-rw-r--r--gcc/cp/cxx-pretty-print.c8
-rw-r--r--gcc/cp/error.c10
-rw-r--r--gcc/cp/lex.c2
-rw-r--r--gcc/cp/mangle.c13
-rw-r--r--gcc/cp/parser.c201
-rw-r--r--gcc/cp/pt.c32
-rw-r--r--gcc/cp/semantics.c164
-rw-r--r--gcc/cp/tree.c6
-rw-r--r--gcc/cp/typeck.c8
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype1.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype2.C59
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype3.C72
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype4.C82
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype5.C38
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype6.C36
21 files changed, 819 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a13f34946cd..283c3430c4e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+2007-07-27 Douglas Gregor <doug.gregor@gmail.com>
+
+ * c-common.h (enum rid): Add RID_DECLTYPE, update RID_LAST_CXX0X.
+
2007-07-26 Kenneth Zadeck <zadeck@naturalbridge.com>
PR middle-end/32749
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 5417c8bb2e9..cb2c56bf5b8 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 3c7b8c6d472..51412983ee0 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,38 @@
+2007-07-27 Douglas Gregor <doug.gregor@gmail.com>
+
+ * 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 <mark@codesourcery.com>
PR c++/32346
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index a0feb30e001..3dd6646efc8 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 e4401712fb5..52cd6ae6d9c 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 ac75e1def8e..9717969639f 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 7e4828ca3bb..7df92561d78 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 f1dc8643a01..6aefb4729bb 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 d708a2bf1f7..7318f493cf3 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
<type> ::= RR <type> # rvalue reference-to
+ <type> ::= Dt <expression> # decltype of an id-expression or
+ # class member access
+ <type> ::= DT <expression> # 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 b8d2b15a083..a7190cb884b 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 fc5af163e1c..d05bfd29e37 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 6b0d4073b0a..b03ec2f59ae 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 772df4cd8f8..97573638a8f 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 51deeb29444..65371c76670 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 9b759425aed..c37bd1d5b00 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2007-07-27 Douglas Gregor <doug.gregor@gmail.com>
+
+ * 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 <rask@sygehus.dk>
* 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 00000000000..447af540dc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype1.C
@@ -0,0 +1,28 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+ static const bool value = true;
+};
+
+const int& foo();
+int i;
+struct A { double x; };
+const A* a = new A();
+
+static_assert(is_same<decltype(foo()), const int&>::value,
+ "type should be const int&");
+static_assert(is_same<decltype(i), int>::value,
+ "type should be int");
+static_assert(is_same<decltype(a->x), double>::value,
+ "type should be double");
+static_assert(is_same<decltype((a->x)), 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 00000000000..65549b4e9b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype2.C
@@ -0,0 +1,59 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+ 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 00000000000..556ae700320
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype3.C
@@ -0,0 +1,72 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+ 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 00000000000..18f27346811
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype4.C
@@ -0,0 +1,82 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+ 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 00000000000..4e8e64b130a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype5.C
@@ -0,0 +1,38 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+ static const bool value = true;
+};
+
+#define CHECK_DECLTYPE(DECLTYPE,RESULT) \
+ static_assert(is_same< DECLTYPE , RESULT >::value, #RESULT)
+
+template<typename F> F create_a();
+
+template<typename F, typename T1>
+decltype(create_a<F&>()(create_a<const T1&>())) forward(F f, const T1& a1)
+{
+ return f(a1);
+}
+
+struct identity {
+ template<typename T>
+ 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 00000000000..c407c182c86
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype6.C
@@ -0,0 +1,36 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>
+{
+ static const bool value = true;
+};
+
+template<typename T> const T& foo();
+
+
+int i;
+
+template<typename T>
+struct A
+{
+ double x;
+};
+
+const A<double>* a = new A<double>();
+
+static_assert(is_same<decltype(foo<int>()), const int&>::value,
+ "type should be const int&");
+static_assert(is_same<decltype(i), int>::value,
+ "type should be int");
+static_assert(is_same<decltype(a->x), double>::value,
+ "type should be double");
+static_assert(is_same<decltype((a->x)), const double&>::value,
+ "type should be const double&");
OpenPOWER on IntegriCloud