aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2008-12-17 14:08:14 -0500
committerJason Merrill <jason@gcc.gnu.org>2008-12-17 14:08:14 -0500
commita77f94e24084115b80f1eb05836d7538b3500c36 (patch)
tree2fc764010bfc532f00bb2946a496b9d1884f5ed0 /gcc
parent3aea2d1ce29ba8a41d54857de2c5bcf1a4dce254 (diff)
downloadgcc-a77f94e24084115b80f1eb05836d7538b3500c36.zip
gcc-a77f94e24084115b80f1eb05836d7538b3500c36.tar.gz
gcc-a77f94e24084115b80f1eb05836d7538b3500c36.tar.bz2
semantics.c (describable_type): New function.
gcc/cp: * semantics.c (describable_type): New function. (finish_decltype_type): Use it for dependent exprs. * cp-tree.h: Declare it. * mangle.c (write_type) [DECLTYPE_TYPE]: Set skip_evaluation. (write_expression): If skip_evaluation, use type stubs. * tree.c (cp_tree_equal): Handle PARM_DECLs from different declarations of a function. * init.c (build_new): Do auto deduction if type is describable. * decl.c (cp_finish_decl): Likewise. * parser.c (cp_parser_omp_for_loop): Likewise. gcc/testsuite: * g++.dg/cpp0x/auto6.C: Test more stuff. * g++.dg/cpp0x/auto12.C: New test. libiberty: * cp-demangle.c (d_expression): Handle rvalue stubs too. [DEMANGLE_COMPONENT_CAST]: Update mangling. (d_print_comp): Avoid extra ", " with empty template argument packs. Remove handling for obsolete T() mangling. From-SVN: r142799
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/init.c2
-rw-r--r--gcc/cp/mangle.c25
-rw-r--r--gcc/cp/parser.c2
-rw-r--r--gcc/cp/semantics.c90
-rw-r--r--gcc/cp/tree.c11
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto12.C52
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto6.C29
11 files changed, 224 insertions, 8 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4b33059..2c681c0 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2008-12-17 Jason Merrill <jason@redhat.com>
+
+ * semantics.c (describable_type): New function.
+ (finish_decltype_type): Use it for dependent exprs.
+ * cp-tree.h: Declare it.
+ * mangle.c (write_type) [DECLTYPE_TYPE]: Set skip_evaluation.
+ (write_expression): If skip_evaluation, use type stubs.
+ * tree.c (cp_tree_equal): Handle PARM_DECLs from different
+ declarations of a function.
+ * init.c (build_new): Do auto deduction if type is describable.
+ * decl.c (cp_finish_decl): Likewise.
+ * parser.c (cp_parser_omp_for_loop): Likewise.
+
2008-12-10 Jason Merrill <jason@redhat.com>
PR c++/35319
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bf22eb4..ff43bc7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4814,6 +4814,7 @@ extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool);
extern tree baselink_for_fns (tree);
extern void finish_static_assert (tree, tree, location_t,
bool);
+extern tree describable_type (tree);
extern tree finish_decltype_type (tree, bool);
extern tree finish_trait_expr (enum cp_trait_kind, tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e786b39..efc7e2e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5496,7 +5496,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
TREE_TYPE (decl) = error_mark_node;
return;
}
- else if (!type_dependent_expression_p (init))
+ else if (describable_type (init))
{
type = TREE_TYPE (decl) = do_auto_deduction (type, init, auto_node);
if (type == error_mark_node)
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index d71b68b..abcf858 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2329,7 +2329,7 @@ build_new (tree placement, tree type, tree nelts, tree init,
orig_init = init;
if (nelts == NULL_TREE && init != void_zero_node && list_length (init) == 1
- && !any_type_dependent_arguments_p (init))
+ && describable_type (TREE_VALUE (init)))
{
tree auto_node = type_uses_auto (type);
if (auto_node)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 36b984e..1ec27c1 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1680,7 +1680,9 @@ write_type (tree type)
write_char ('t');
else
write_char ('T');
+ ++skip_evaluation;
write_expression (DECLTYPE_TYPE_EXPR (type));
+ --skip_evaluation;
write_char ('E');
break;
@@ -2139,9 +2141,28 @@ write_member_name (tree member)
static void
write_expression (tree expr)
{
- enum tree_code code;
+ enum tree_code code = TREE_CODE (expr);
- code = TREE_CODE (expr);
+ /* Inside decltype we can simplify some expressions, since we're only
+ interested in the type. */
+ if (skip_evaluation)
+ {
+ tree type = describable_type (expr);
+ if (type == NULL_TREE)
+ ;
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ write_string ("sT");
+ write_type (TREE_TYPE (type));
+ return;
+ }
+ else
+ {
+ write_string ("sR");
+ write_type (type);
+ return;
+ }
+ }
/* Skip NOP_EXPRs. They can occur when (say) a pointer argument
is converted (via qualification conversions) to another
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 45abd24..79be488 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -21159,7 +21159,7 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses)
&is_direct_init,
&is_non_constant_init);
- if (auto_node && !type_dependent_expression_p (init))
+ if (auto_node && describable_type (init))
{
TREE_TYPE (decl)
= do_auto_deduction (TREE_TYPE (decl), init,
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e0ae6ff..d5efb83 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4438,12 +4438,79 @@ finish_static_assert (tree condition, tree message, location_t location,
}
}
+/* Returns decltype((EXPR)) for cases where we can drop the decltype and
+ just return the type even though EXPR is a type-dependent expression.
+ The ABI specifies which cases this applies to, which is a subset of the
+ possible cases. */
+
+tree
+describable_type (tree expr)
+{
+ tree type = NULL_TREE;
+
+ /* processing_template_decl isn't set when we're called from the mangling
+ code, so bump it now. */
+ ++processing_template_decl;
+ if (! type_dependent_expression_p (expr)
+ && ! type_unknown_p (expr))
+ {
+ type = TREE_TYPE (expr);
+ if (real_lvalue_p (expr))
+ type = build_reference_type (type);
+ }
+ --processing_template_decl;
+
+ if (type)
+ return type;
+
+ switch (TREE_CODE (expr))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case FUNCTION_DECL:
+ /* Named rvalue reference becomes lvalue. */
+ type = build_reference_type (non_reference (TREE_TYPE (expr)));
+ break;
+
+ case NEW_EXPR:
+ case CONST_DECL:
+ case TEMPLATE_PARM_INDEX:
+ case CAST_EXPR:
+ case STATIC_CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
+ case CONST_CAST_EXPR:
+ case DYNAMIC_CAST_EXPR:
+ type = TREE_TYPE (expr);
+ break;
+
+ case INDIRECT_REF:
+ {
+ tree ptrtype = describable_type (TREE_OPERAND (expr, 0));
+ if (ptrtype && POINTER_TYPE_P (ptrtype))
+ type = build_reference_type (TREE_TYPE (ptrtype));
+ }
+ break;
+
+ default:
+ if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_constant)
+ type = TREE_TYPE (expr);
+ break;
+ }
+
+ if (type && type_uses_auto (type))
+ return NULL_TREE;
+ else
+ return type;
+}
+
/* 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)
{
@@ -4464,6 +4531,29 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
if (type_dependent_expression_p (expr))
{
+ if (id_expression_or_member_access_p)
+ {
+ switch (TREE_CODE (expr))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case FUNCTION_DECL:
+ case CONST_DECL:
+ case TEMPLATE_PARM_INDEX:
+ type = TREE_TYPE (expr);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ type = describable_type (expr);
+
+ if (type && !type_uses_auto (type))
+ return type;
+
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2ae6543..1f2c631 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1857,8 +1857,17 @@ cp_tree_equal (tree t1, tree t2)
return false;
return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
- case VAR_DECL:
case PARM_DECL:
+ /* For comparing uses of parameters in late-specified return types
+ with an out-of-class definition of the function. */
+ if ((!DECL_CONTEXT (t1) || !DECL_CONTEXT (t2))
+ && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+ && DECL_NAME (t1) == DECL_NAME (t2))
+ return true;
+ else
+ return false;
+
+ case VAR_DECL:
case CONST_DECL:
case FUNCTION_DECL:
case TEMPLATE_DECL:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 74b39a4..11a6a70 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-12-17 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/auto6.C: Test more stuff.
+ * g++.dg/cpp0x/auto12.C: New test.
+
2008-12-17 Daniel Kraft <d@domob.eu>
PR fortran/38137
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto12.C b/gcc/testsuite/g++.dg/cpp0x/auto12.C
new file mode 100644
index 0000000..94652cb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto12.C
@@ -0,0 +1,52 @@
+// More auto/decltype mangling tests.
+// { dg-options "-std=c++0x" }
+
+template <class T>
+struct B
+{
+ static int i;
+};
+
+int&& x();
+
+template <class T>
+struct A
+{
+ static int i;
+ static int &ir;
+ static int &&irr;
+ template <class U>
+ auto f(U u) -> decltype (u + i);
+ template <class U>
+ auto fr(U u) -> decltype (u + ir);
+ template <class U>
+ auto frr(U u) -> decltype (u + irr);
+ template <class U>
+ auto g(U u) -> decltype (u + sizeof (i));
+ template <class U>
+ auto h(U u) -> decltype (u + B<U>::i);
+ template <class U>
+ auto j(U u) -> decltype (u + x());
+};
+
+template<class T> template<class U>
+auto A<T>::f(U u) -> decltype (u + i)
+{
+ return u + i;
+}
+
+int main()
+{
+ // { dg-final { scan-assembler "_ZN1AIiE1fIiEEDTplsTT_sTiES2_" } }
+ A<int>().f(1);
+ // { dg-final { scan-assembler "_ZN1AIiE2frIiEEDTplsTT_sTiES2_" } }
+ A<int>().fr(1);
+ // { dg-final { scan-assembler "_ZN1AIiE3frrIiEEDTplsTT_sTiES2_" } }
+ A<int>().frr(1);
+ // { dg-final { scan-assembler "_ZN1AIiE1gIiEEDTplsTT_sRjES2_" } }
+ A<int>().g(1);
+ // { dg-final { scan-assembler "_ZN1AIiE1hIiEEDTplsTT_sr1BIS2_E1iES2_" } }
+ A<int>().h(1);
+ // { dg-final { scan-assembler "_ZN1AIiE1jIiEEDTplsTT_sRiES2_" } }
+ A<int>().j(1);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto6.C b/gcc/testsuite/g++.dg/cpp0x/auto6.C
index d2bcfedb..7d659c7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto6.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto6.C
@@ -30,6 +30,12 @@ auto add3(T t, U u) -> decltype (ag(t,u))
return ag(t,u);
}
+template<class T, class U>
+decltype(*(T*)0+*(U*)0) add4(T t, U u)
+{
+ return t+u;
+}
+
template <class T>
struct A
{
@@ -72,13 +78,28 @@ auto k(T t, U u, V v) -> decltype (t.U::template B<V>::MEM)
return t.U::template B<V>::MEM;
}
+// For these two examples we can elide the 'decltype' and just mangle the type.
+template <class T>
+auto l(T t) -> decltype (t)
+{
+ return t;
+}
+
+template <class T, T u>
+auto m(T t) -> decltype (u)
+{
+ return t;
+}
+
A<int> a, *p;
int main()
{
- // { dg-final { scan-assembler "_Z3addIidEDTplsTT_sTT0_ES0_S1_" } }
+ // { dg-final { scan-assembler "_Z3addIidEDTplsTT_sTT0_ES0_S1_" } }
auto i = add(1, 2.0);
- // { dg-final { scan-assembler "_Z4add2IidEDTplcvT_vcvT0_vES0_S1_" } }
+ // { dg-final { scan-assembler "_Z4add4IidEDTplsTT_sTT0_ES0_S1_" } }
+ auto i4 = add4(1, 2.0);
+ // { dg-final { scan-assembler "_Z4add2IidEDTplsRT_sRT0_ES0_S1_" } }
auto i2 = add2(1, 2.0);
// { dg-final { scan-assembler "_Z4add3IidEDTclL_Z2agEsTT_sTT0_EES0_S1_" } }
auto i3 = add3(1, 2.0);
@@ -90,4 +111,8 @@ int main()
h(a,1.0);
// { dg-final { scan-assembler "_Z1kI1C1AIiE1DEDtdtsTT_srNT0_1BIT1_EE3MEMES4_S5_S7_" } }
k( C(), A<int>(), D() );
+ // { dg-final { scan-assembler "_Z1lIiET_S0_" } }
+ l(1);
+ // { dg-final { scan-assembler "_Z1mIiLi1EET_S0_" } }
+ m<int,1>(1);
}