cp-tree.h (AUTO_IS_DECLTYPE): New.
N3582 * cp-tree.h (AUTO_IS_DECLTYPE): New. * parser.c (cp_parser_decltype): Handle decltype(auto). (cp_parser_type_id_1): Allow auto without a late-specified return in C++1y. (cp_parser_primary_expression): Use the return value of finish_parenthesized_expr. (cp_parser_transaction_expression): Likewise. * semantics.c (force_paren_expr): New. (finish_parenthesized_expr): Use it. * call.c (build_conditional_expr_1): Likewise. * pt.c (do_auto_deduction): Handle decltype(auto). (tsubst_copy): Handle PAREN_EXPR. (tsubst_copy_and_build): Likewise. * error.c (dump_expr): Handle PAREN_EXPR. * cxx-pretty-print.c (pp_cxx_expression): Likewise. * mangle.c (write_expression): Ignore PAREN_EXPR. * parser.c (cp_parser_decltype_expr): Split out... (cp_parser_decltype): ...from here. From-SVN: r197248
This commit is contained in:
parent
15914ac8b1
commit
10c6dc8e39
@ -1,5 +1,23 @@
|
||||
2013-03-29 Jason Merrill <jason@redhat.com>
|
||||
|
||||
N3582
|
||||
* cp-tree.h (AUTO_IS_DECLTYPE): New.
|
||||
* parser.c (cp_parser_decltype): Handle decltype(auto).
|
||||
(cp_parser_type_id_1): Allow auto without a late-specified
|
||||
return in C++1y.
|
||||
(cp_parser_primary_expression): Use the return value of
|
||||
finish_parenthesized_expr.
|
||||
(cp_parser_transaction_expression): Likewise.
|
||||
* semantics.c (force_paren_expr): New.
|
||||
(finish_parenthesized_expr): Use it.
|
||||
* call.c (build_conditional_expr_1): Likewise.
|
||||
* pt.c (do_auto_deduction): Handle decltype(auto).
|
||||
(tsubst_copy): Handle PAREN_EXPR.
|
||||
(tsubst_copy_and_build): Likewise.
|
||||
* error.c (dump_expr): Handle PAREN_EXPR.
|
||||
* cxx-pretty-print.c (pp_cxx_expression): Likewise.
|
||||
* mangle.c (write_expression): Ignore PAREN_EXPR.
|
||||
|
||||
* parser.c (cp_parser_decltype_expr): Split out...
|
||||
(cp_parser_decltype): ...from here.
|
||||
|
||||
|
@ -4845,6 +4845,8 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3,
|
||||
lvalue, we must add a NON_LVALUE_EXPR. */
|
||||
result = rvalue (result);
|
||||
}
|
||||
else
|
||||
result = force_paren_expr (result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ c-common.h, not after.
|
||||
4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
|
||||
5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
|
||||
ENUM_FIXED_UNDERLYING_TYPE_P (in ENUMERAL_TYPE)
|
||||
AUTO_IS_DECLTYPE (in TEMPLATE_TYPE_PARM)
|
||||
6: TYPE_DEPENDENT_P_VALID
|
||||
|
||||
Usage of DECL_LANG_FLAG_?:
|
||||
@ -4604,6 +4605,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
|
||||
#define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
|
||||
(TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE)))
|
||||
|
||||
/* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */
|
||||
#define AUTO_IS_DECLTYPE(NODE) \
|
||||
(TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE)))
|
||||
|
||||
/* These constants can used as bit flags in the process of tree formatting.
|
||||
|
||||
TFF_PLAIN_IDENTIFIER: unqualified part of a name.
|
||||
@ -5659,6 +5664,7 @@ extern tree finish_asm_stmt (int, tree, tree, tree, tree,
|
||||
extern tree finish_label_stmt (tree);
|
||||
extern void finish_label_decl (tree);
|
||||
extern tree finish_parenthesized_expr (tree);
|
||||
extern tree force_paren_expr (tree);
|
||||
extern tree finish_non_static_data_member (tree, tree, tree);
|
||||
extern tree begin_stmt_expr (void);
|
||||
extern tree finish_stmt_expr_expr (tree, tree);
|
||||
|
@ -1167,6 +1167,12 @@ pp_cxx_expression (cxx_pretty_printer *pp, tree t)
|
||||
pp_cxx_ws_string (pp, "<lambda>");
|
||||
break;
|
||||
|
||||
case PAREN_EXPR:
|
||||
pp_cxx_left_paren (pp);
|
||||
pp_cxx_expression (pp, TREE_OPERAND (t, 0));
|
||||
pp_cxx_right_paren (pp);
|
||||
break;
|
||||
|
||||
default:
|
||||
pp_c_expression (pp_c_base (pp), t);
|
||||
break;
|
||||
|
@ -2506,6 +2506,12 @@ dump_expr (tree t, int flags)
|
||||
pp_string (cxx_pp, M_("<lambda>"));
|
||||
break;
|
||||
|
||||
case PAREN_EXPR:
|
||||
pp_cxx_left_paren (cxx_pp);
|
||||
dump_expr (TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
|
||||
pp_cxx_right_paren (cxx_pp);
|
||||
break;
|
||||
|
||||
/* This list is incomplete, but should suffice for now.
|
||||
It is very important that `sorry' does not call
|
||||
`report_error_function'. That could cause an infinite loop. */
|
||||
|
@ -2555,6 +2555,8 @@ write_expression (tree expr)
|
||||
is converted (via qualification conversions) to another
|
||||
type. */
|
||||
while (TREE_CODE (expr) == NOP_EXPR
|
||||
/* Parentheses aren't mangled. */
|
||||
|| code == PAREN_EXPR
|
||||
|| TREE_CODE (expr) == NON_LVALUE_EXPR)
|
||||
{
|
||||
expr = TREE_OPERAND (expr, 0);
|
||||
|
@ -4106,7 +4106,7 @@ cp_parser_primary_expression (cp_parser *parser,
|
||||
example, the expression is of the form `A::B', since
|
||||
`&A::B' might be a pointer-to-member, but `&(A::B)' is
|
||||
not. */
|
||||
finish_parenthesized_expr (expr);
|
||||
expr = finish_parenthesized_expr (expr);
|
||||
/* DR 705: Wrapping an unqualified name in parentheses
|
||||
suppresses arg-dependent lookup. We want to pass back
|
||||
CP_ID_KIND_QUALIFIED for suppressing vtable lookup
|
||||
@ -11399,7 +11399,9 @@ cp_parser_decltype_expr (cp_parser *parser,
|
||||
/* Parse a `decltype' type. Returns the type.
|
||||
|
||||
simple-type-specifier:
|
||||
decltype ( expression ) */
|
||||
decltype ( expression )
|
||||
C++14 proposal:
|
||||
decltype ( auto ) */
|
||||
|
||||
static tree
|
||||
cp_parser_decltype (cp_parser *parser)
|
||||
@ -11427,6 +11429,18 @@ cp_parser_decltype (cp_parser *parser)
|
||||
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
|
||||
return error_mark_node;
|
||||
|
||||
/* decltype (auto) */
|
||||
if (cxx_dialect >= cxx1y
|
||||
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
|
||||
{
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
|
||||
return error_mark_node;
|
||||
expr = make_auto ();
|
||||
AUTO_IS_DECLTYPE (expr) = true;
|
||||
goto rewrite;
|
||||
}
|
||||
|
||||
/* Types cannot be defined in a `decltype' expression. Save away the
|
||||
old message. */
|
||||
saved_message = parser->type_definition_forbidden_message;
|
||||
@ -11485,6 +11499,7 @@ cp_parser_decltype (cp_parser *parser)
|
||||
expr = finish_decltype_type (expr, id_expression_or_member_access_p,
|
||||
tf_warning_or_error);
|
||||
|
||||
rewrite:
|
||||
/* Replace the decltype with a CPP_DECLTYPE so we don't need to parse
|
||||
it again. */
|
||||
start_token->type = CPP_DECLTYPE;
|
||||
@ -17207,6 +17222,7 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg,
|
||||
abstract_declarator = NULL;
|
||||
|
||||
if (type_specifier_seq.type
|
||||
&& cxx_dialect < cxx1y
|
||||
&& type_uses_auto (type_specifier_seq.type))
|
||||
{
|
||||
/* A type-id with type 'auto' is only ok if the abstract declarator
|
||||
@ -28003,7 +28019,7 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
|
||||
cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
|
||||
|
||||
expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
|
||||
finish_parenthesized_expr (expr);
|
||||
expr = finish_parenthesized_expr (expr);
|
||||
|
||||
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
|
||||
}
|
||||
|
62
gcc/cp/pt.c
62
gcc/cp/pt.c
@ -12303,6 +12303,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
case TYPEID_EXPR:
|
||||
case REALPART_EXPR:
|
||||
case IMAGPART_EXPR:
|
||||
case PAREN_EXPR:
|
||||
return build1
|
||||
(code, tsubst (TREE_TYPE (t), args, complain, in_decl),
|
||||
tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
|
||||
@ -14549,6 +14550,9 @@ tsubst_copy_and_build (tree t,
|
||||
RETURN (tsubst_expr(t, args, complain, in_decl,
|
||||
integral_constant_expression_p));
|
||||
|
||||
case PAREN_EXPR:
|
||||
RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, 0))));
|
||||
|
||||
default:
|
||||
/* Handle Objective-C++ constructs, if appropriate. */
|
||||
{
|
||||
@ -20593,9 +20597,7 @@ listify_autos (tree type, tree auto_node)
|
||||
tree
|
||||
do_auto_deduction (tree type, tree init, tree auto_node)
|
||||
{
|
||||
tree parms, tparms, targs;
|
||||
tree args[1];
|
||||
int val;
|
||||
tree targs;
|
||||
|
||||
if (init == error_mark_node)
|
||||
return error_mark_node;
|
||||
@ -20614,32 +20616,42 @@ do_auto_deduction (tree type, tree init, tree auto_node)
|
||||
|
||||
init = resolve_nondeduced_context (init);
|
||||
|
||||
parms = build_tree_list (NULL_TREE, type);
|
||||
args[0] = 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, 1, 0,
|
||||
DEDUCE_CALL, LOOKUP_NORMAL,
|
||||
/*explain_p=*/false);
|
||||
if (val > 0)
|
||||
if (AUTO_IS_DECLTYPE (auto_node))
|
||||
{
|
||||
if (processing_template_decl)
|
||||
/* Try again at instantiation time. */
|
||||
return type;
|
||||
if (type && type != error_mark_node)
|
||||
/* If type is error_mark_node a diagnostic must have been
|
||||
emitted by now. Also, having a mention to '<type error>'
|
||||
in the diagnostic is not really useful to the user. */
|
||||
bool id = (DECL_P (init) || TREE_CODE (init) == COMPONENT_REF);
|
||||
TREE_VEC_ELT (targs, 0)
|
||||
= finish_decltype_type (init, id, tf_warning_or_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree parms = build_tree_list (NULL_TREE, type);
|
||||
tree tparms = make_tree_vec (1);
|
||||
int val;
|
||||
|
||||
TREE_VEC_ELT (tparms, 0)
|
||||
= build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
|
||||
val = type_unification_real (tparms, targs, parms, &init, 1, 0,
|
||||
DEDUCE_CALL, LOOKUP_NORMAL,
|
||||
/*explain_p=*/false);
|
||||
if (val > 0)
|
||||
{
|
||||
if (cfun && auto_node == current_function_auto_return_pattern
|
||||
&& LAMBDA_FUNCTION_P (current_function_decl))
|
||||
error ("unable to deduce lambda return type from %qE", init);
|
||||
else
|
||||
error ("unable to deduce %qT from %qE", type, init);
|
||||
if (processing_template_decl)
|
||||
/* Try again at instantiation time. */
|
||||
return type;
|
||||
if (type && type != error_mark_node)
|
||||
/* If type is error_mark_node a diagnostic must have been
|
||||
emitted by now. Also, having a mention to '<type error>'
|
||||
in the diagnostic is not really useful to the user. */
|
||||
{
|
||||
if (cfun && auto_node == current_function_auto_return_pattern
|
||||
&& LAMBDA_FUNCTION_P (current_function_decl))
|
||||
error ("unable to deduce lambda return type from %qE", init);
|
||||
else
|
||||
error ("unable to deduce %qT from %qE", type, init);
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* If the list of declarators contains more than one declarator, the type
|
||||
|
@ -1507,6 +1507,38 @@ finish_mem_initializers (tree mem_inits)
|
||||
emit_mem_initializers (mem_inits);
|
||||
}
|
||||
|
||||
/* Obfuscate EXPR if it looks like an id-expression or member access so
|
||||
that the call to finish_decltype in do_auto_deduction will give the
|
||||
right result. */
|
||||
|
||||
tree
|
||||
force_paren_expr (tree expr)
|
||||
{
|
||||
/* This is only needed for decltype(auto) in C++14. */
|
||||
if (cxx_dialect < cxx1y)
|
||||
return expr;
|
||||
|
||||
if (!DECL_P (expr) && TREE_CODE (expr) != COMPONENT_REF
|
||||
&& TREE_CODE (expr) != SCOPE_REF)
|
||||
return expr;
|
||||
|
||||
if (processing_template_decl)
|
||||
expr = build1 (PAREN_EXPR, TREE_TYPE (expr), expr);
|
||||
else
|
||||
{
|
||||
cp_lvalue_kind kind = lvalue_kind (expr);
|
||||
if ((kind & ~clk_class) != clk_none)
|
||||
{
|
||||
tree type = unlowered_expr_type (expr);
|
||||
bool rval = !!(kind & clk_rvalueref);
|
||||
type = cp_build_reference_type (type, rval);
|
||||
expr = build_static_cast (type, expr, tf_warning_or_error);
|
||||
}
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Finish a parenthesized expression EXPR. */
|
||||
|
||||
tree
|
||||
@ -1525,6 +1557,8 @@ finish_parenthesized_expr (tree expr)
|
||||
if (TREE_CODE (expr) == STRING_CST)
|
||||
PAREN_STRING_LITERAL_P (expr) = 1;
|
||||
|
||||
expr = force_paren_expr (expr);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
50
gcc/testsuite/g++.dg/cpp1y/auto-fn15.C
Normal file
50
gcc/testsuite/g++.dg/cpp1y/auto-fn15.C
Normal file
@ -0,0 +1,50 @@
|
||||
// { dg-options "-std=c++1y -Wno-return-local-addr" }
|
||||
|
||||
template<class,class> struct same_type;
|
||||
template<class T> struct same_type<T,T> {};
|
||||
|
||||
int& f();
|
||||
int i;
|
||||
|
||||
decltype(auto) g() { return f(); }
|
||||
decltype(auto) h1() { return i; }
|
||||
decltype(auto) h2() { return (i); }
|
||||
decltype(auto) h2a() { return 0,i; }
|
||||
|
||||
struct A { int i; };
|
||||
A a;
|
||||
|
||||
decltype(auto) h3() { return a.i; }
|
||||
decltype(auto) h4() { return (a.i); }
|
||||
|
||||
template <class T>
|
||||
decltype(auto) h5(T t) { return t.i; }
|
||||
template <class T>
|
||||
decltype(auto) h6(T t) { return (t.i); }
|
||||
|
||||
int main()
|
||||
{
|
||||
decltype(auto) i = f();
|
||||
same_type<decltype(i),int&>();
|
||||
decltype(auto) i2 = i;
|
||||
same_type<decltype(i2),int&>();
|
||||
decltype(auto) i3 = ::i;
|
||||
same_type<decltype(i3),int>();
|
||||
decltype(auto) i4 = (::i);
|
||||
same_type<decltype(i4),int&>();
|
||||
decltype(auto) i5 = a.i;
|
||||
same_type<decltype(i5),int>();
|
||||
decltype(auto) i6 = (a.i);
|
||||
same_type<decltype(i6),int&>();
|
||||
decltype(auto) i7 = true ? ::i : ::i;
|
||||
same_type<decltype(i7),int&>();
|
||||
|
||||
same_type<decltype(g()),int&>();
|
||||
same_type<decltype(h1()),int>();
|
||||
same_type<decltype(h2()),int&>();
|
||||
same_type<decltype(h2a()),int&>();
|
||||
same_type<decltype(h3()),int>();
|
||||
same_type<decltype(h4()),int&>();
|
||||
same_type<decltype(h5(a)),int>();
|
||||
same_type<decltype(h6(a)),int&>();
|
||||
}
|
12
gcc/testsuite/g++.dg/cpp1y/auto-fn16.C
Normal file
12
gcc/testsuite/g++.dg/cpp1y/auto-fn16.C
Normal file
@ -0,0 +1,12 @@
|
||||
// { dg-options -std=c++1y }
|
||||
|
||||
template<class,class> struct ST;
|
||||
template<class T> struct ST<T,T> {};
|
||||
|
||||
int j;
|
||||
auto x3 = []()->auto&& { return j; }; // OK: return type is int&
|
||||
|
||||
int main()
|
||||
{
|
||||
ST<decltype(x3()),int&>();
|
||||
}
|
22
gcc/testsuite/g++.dg/cpp1y/auto-fn17.C
Normal file
22
gcc/testsuite/g++.dg/cpp1y/auto-fn17.C
Normal file
@ -0,0 +1,22 @@
|
||||
// { dg-options -std=c++1y }
|
||||
// { dg-do run }
|
||||
|
||||
int c;
|
||||
int d;
|
||||
|
||||
struct A
|
||||
{
|
||||
A() { ++c; }
|
||||
A(const A&) { ++c; }
|
||||
~A() { ++d; }
|
||||
};
|
||||
|
||||
A g() { return A(); }
|
||||
decltype(auto) f() { return g(); }
|
||||
|
||||
int main()
|
||||
{
|
||||
f();
|
||||
if (c < 1 || c != d)
|
||||
__builtin_abort ();
|
||||
}
|
13
gcc/testsuite/g++.dg/cpp1y/mangle1.C
Normal file
13
gcc/testsuite/g++.dg/cpp1y/mangle1.C
Normal file
@ -0,0 +1,13 @@
|
||||
// Test that the parens don't show up in the mangling
|
||||
// { dg-options "-std=c++1y -Wno-return-local-addr" }
|
||||
// { dg-final { scan-assembler "_Z1gI1AEDTdtfp_1iET_" } }
|
||||
|
||||
struct A { int i; };
|
||||
|
||||
template <class T>
|
||||
auto g(T t)->decltype((t.i)) { return t.i; }
|
||||
|
||||
int main()
|
||||
{
|
||||
g(A());
|
||||
}
|
Loading…
Reference in New Issue
Block a user