This patch adds support for use of 'this' (implicitly or explicitly) in
the trailing-return-type of a member function.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 8154a9854f1d5ff3407af1707d112899eb39f013
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Jun 29 15:19:46 2011 -0400
DR 1207
PR c++/49003
* cp-tree.h (struct saved_scope): Add x_current_class_ptr,
x_current_class_ref.
(current_class_ptr, current_class_ref): Use them.
* decl.c (build_this_parm): Handle getting the class type.
* parser.c (cp_parser_late_return_type_opt): Set up 'this'
for use within the trailing return type.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 55c88e3..ef25c97 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -953,6 +953,10 @@ struct GTY(()) saved_scope {
struct cp_binding_level *x_previous_class_level;
tree x_saved_tree;
+ /* Only used for uses of this in trailing return type. */
+ tree x_current_class_ptr;
+ tree x_current_class_ref;
+
int x_processing_template_decl;
int x_processing_specialization;
BOOL_BITFIELD x_processing_explicit_instantiation : 1;
@@ -1070,12 +1074,14 @@ struct GTY(()) language_function {
PARM_DECL for the `this' pointer. The current_class_ref is an
expression for `*this'. */
-#define current_class_ptr \
- (cfun && cp_function_chain \
- ? cp_function_chain->x_current_class_ptr : NULL_TREE)
-#define current_class_ref \
- ((cfun && cp_function_chain) \
- ? cp_function_chain->x_current_class_ref : NULL_TREE)
+#define current_class_ptr \
+ (*(cfun && cp_function_chain \
+ ? &cp_function_chain->x_current_class_ptr \
+ : &scope_chain->x_current_class_ptr))
+#define current_class_ref \
+ (*(cfun && cp_function_chain \
+ ? &cp_function_chain->x_current_class_ref \
+ : &scope_chain->x_current_class_ref))
/* The EH_SPEC_BLOCK for the exception-specifiers for the current
function, if any. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b8435a6..94d686d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7001,7 +7001,14 @@ build_this_parm (tree type, cp_cv_quals quals)
tree parm;
cp_cv_quals this_quals;
- this_type = type_of_this_parm (type);
+ if (CLASS_TYPE_P (type))
+ {
+ this_type
+ = cp_build_qualified_type (type, quals & ~TYPE_QUAL_RESTRICT);
+ this_type = build_pointer_type (this_type);
+ }
+ else
+ this_type = type_of_this_parm (type);
/* The `this' parameter is implicitly `const'; it cannot be
assigned to. */
this_quals = (quals & TYPE_QUAL_RESTRICT) | TYPE_QUAL_CONST;
@@ -12675,6 +12682,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
cp_function_chain->x_current_class_ref
= cp_build_indirect_ref (t, RO_NULL, tf_warning_or_error);
+ /* Set this second to avoid shortcut in cp_build_indirect_ref. */
cp_function_chain->x_current_class_ptr = t;
/* Constructors and destructors need to know whether they're "in
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f1b7976..d79326d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1696,7 +1696,7 @@ static cp_cv_quals cp_parser_cv_qualifier_seq_opt
static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
(cp_parser *);
static tree cp_parser_late_return_type_opt
- (cp_parser *);
+ (cp_parser *, cp_cv_quals);
static tree cp_parser_declarator_id
(cp_parser *, bool);
static tree cp_parser_type_id
@@ -14968,7 +14968,7 @@ cp_parser_direct_declarator (cp_parser* parser,
virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
late_return
- = cp_parser_late_return_type_opt (parser);
+ = cp_parser_late_return_type_opt (parser, cv_quals);
/* Create the function-declarator. */
declarator = make_call_declarator (declarator,
@@ -15537,9 +15537,10 @@ cp_parser_virt_specifier_seq_opt (cp_parser* parser)
Returns the type indicated by the type-id. */
static tree
-cp_parser_late_return_type_opt (cp_parser* parser)
+cp_parser_late_return_type_opt (cp_parser* parser, cp_cv_quals quals)
{
cp_token *token;
+ tree type;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
@@ -15550,7 +15551,23 @@ cp_parser_late_return_type_opt (cp_parser* parser)
/* Consume the ->. */
cp_lexer_consume_token (parser->lexer);
- return cp_parser_trailing_type_id (parser);
+ if (current_class_type)
+ {
+ /* DR 1207: 'this' is in scope in the trailing return type. */
+ tree this_parm = build_this_parm (current_class_type, quals);
+ gcc_assert (current_class_ptr == NULL_TREE);
+ current_class_ref
+ = cp_build_indirect_ref (this_parm, RO_NULL, tf_warning_or_error);
+ /* Set this second to avoid shortcut in cp_build_indirect_ref. */
+ current_class_ptr = this_parm;
+ }
+
+ type = cp_parser_trailing_type_id (parser);
+
+ if (current_class_type)
+ current_class_ptr = current_class_ref = NULL_TREE;
+
+ return type;
}
/* Parse a declarator-id.
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr45908.C b/gcc/testsuite/g++.dg/cpp0x/pr45908.C
index 3a85088..45399b5 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr45908.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr45908.C
@@ -14,5 +14,5 @@ struct vector {
class block {
vector v;
auto end() const -> decltype(v.begin())
- { return v.begin(); } // { dg-error "could not convert" }
+ { return v.begin(); }
};
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing6.C b/gcc/testsuite/g++.dg/cpp0x/trailing6.C
new file mode 100644
index 0000000..3476e90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing6.C
@@ -0,0 +1,6 @@
+// PR c++/49003
+// { dg-options -std=c++0x }
+
+struct A {
+ auto a() const -> decltype(this) { return this; }
+};