Now that we have reasonable terminology for talking about expressions
involving rvalue references, we can ditch the clumsy rule about decltype
of a call in favor of just saying that decltype of an xvalue is an
rvalue reference.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 2ac0fa349f5a2c3bef8eda3ef73c550ee8d3e71b
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Mar 17 10:35:40 2011 -0400
Core 1212
* semantics.c (finish_decltype_type): Return T&& for xvalue.
* typeck.c (unlowered_expr_type): Preserve cv-quals.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7519d26..cafca56 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4787,7 +4787,6 @@ finish_decltype_type (tree expr, bool
id_expression_or_member_access_p)
&& processing_template_decl
&& TREE_CODE (expr) == COMPONENT_REF))
{
- treat_as_dependent:
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
@@ -4899,91 +4898,34 @@ finish_decltype_type (tree expr, bool
id_expression_or_member_access_p)
}
else
{
- /* Expressions of reference type are sometimes wrapped in
- INDIRECT_REFs. INDIRECT_REFs are just internal compiler
- representation, not part of the language, so we have to look
- through them. */
- if (TREE_CODE (expr) == INDIRECT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
- == REFERENCE_TYPE)
- expr = TREE_OPERAND (expr, 0);
+ /* Within a lambda-expression:
- if (TREE_CODE (expr) == CALL_EXPR)
- {
- /* 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. */
- tree fndecl = get_callee_fndecl (expr);
- if (fndecl && fndecl != error_mark_node)
- type = TREE_TYPE (TREE_TYPE (fndecl));
- else
- {
- tree target_type = TREE_TYPE (CALL_EXPR_FN (expr));
- if ((TREE_CODE (target_type) == REFERENCE_TYPE
- || TREE_CODE (target_type) == POINTER_TYPE)
- && (TREE_CODE (TREE_TYPE (target_type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (target_type)) == METHOD_TYPE))
- type = TREE_TYPE (TREE_TYPE (target_type));
- else if (processing_template_decl)
- /* Within a template finish_call_expr doesn't resolve
- CALL_EXPR_FN, so even though this decltype isn't really
- dependent let's defer resolving it. */
- goto treat_as_dependent;
- else
- sorry ("unable to determine the declared type of expression
%<%E%>",
- expr);
- }
- }
- 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);
- }
- /* Within a lambda-expression:
-
- Every occurrence of decltype((x)) where x is a possibly
- parenthesized id-expression that names an entity of
- automatic storage duration is treated as if x were
- transformed into an access to a corresponding data member
- of the closure type that would have been declared if x
- were a use of the denoted entity. */
- else if (outer_automatic_var_p (expr)
- && current_function_decl
- && LAMBDA_FUNCTION_P (current_function_decl))
- type = capture_decltype (expr);
- 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 (type == error_mark_node)
- return error_mark_node;
- else 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_REF_IS_RVALUE (type))
- type = build_reference_type (non_reference (type));
- }
- else
- type = non_reference (type);
- }
- }
+ Every occurrence of decltype((x)) where x is a possibly
+ parenthesized id-expression that names an entity of
+ automatic storage duration is treated as if x were
+ transformed into an access to a corresponding data member
+ of the closure type that would have been declared if x
+ were a use of the denoted entity. */
+ if (outer_automatic_var_p (expr)
+ && current_function_decl
+ && LAMBDA_FUNCTION_P (current_function_decl))
+ type = capture_decltype (expr);
+ else if (error_operand_p (expr))
+ type = error_mark_node;
+ else 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 (TREE_TYPE (expr));
+ else
+ {
+ /* Otherwise, where T is the type of e, if e is an lvalue,
+ decltype(e) is defined as T&; if an xvalue, T&&; otherwise, T. */
+ cp_lvalue_kind clk = lvalue_kind (expr);
+ type = unlowered_expr_type (expr);
+ gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
+ if (clk != clk_none && !(clk & clk_class))
+ type = cp_build_reference_type (type, (clk & clk_rvalueref));
+ }
}
if (!type || type == unknown_type_node)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 03aa49e..955ff57 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1768,10 +1768,13 @@ tree
unlowered_expr_type (const_tree exp)
{
tree type;
+ tree etype = TREE_TYPE (exp);
type = is_bitfield_expr_with_lowered_type (exp);
- if (!type)
- type = TREE_TYPE (exp);
+ if (type)
+ type = cp_build_qualified_type (type, cp_type_quals (etype));
+ else
+ type = etype;
return type;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype-1212.C
b/gcc/testsuite/g++.dg/cpp0x/decltype-1212.C
new file mode 100644
index 0000000..38393d3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype-1212.C
@@ -0,0 +1,11 @@
+// Core 1212
+// { dg-options -std=c++0x }
+
+template <class T, class U> struct assert_same_type;
+template <class T> struct assert_same_type<T,T> {};
+
+int main()
+{
+ int i;
+ assert_same_type<int&&,decltype(static_cast<int&&>(i))>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-return.C
b/gcc/testsuite/g++.dg/cpp0x/rv-return.C
index e52101f..3ab6598 100644
--- a/gcc/testsuite/g++.dg/cpp0x/rv-return.C
+++ b/gcc/testsuite/g++.dg/cpp0x/rv-return.C
@@ -7,12 +7,12 @@ template<typename T> struct same_type<T, T> {};
int const f() { return 0; }
int &&r = f(); // binding "int&&" to "int" should succeed
-same_type<decltype(f()), int const> s1;
+same_type<decltype(f()), int> s1;
same_type<decltype(0,f()), int> s2;
template <class T>
T const g() { return 0; }
int &&r2 = g<int>();
-same_type<decltype(g<int>()), int const> s3;
+same_type<decltype(g<int>()), int> s3;
same_type<decltype(0,g<int>()), int> s4;