Implement N3271
Implement N3271 * parser.c (cp_convert_range_for): Split into cp_parser_perform_range_for_lookup. (cp_parser_perform_range_for_lookup): New. (cp_parser_range_for_member_function): New. (cp_parser_for_init_statement): Correct error message. * semantics.c (finish_call_expr): Accept COMPONENT_REF. From-SVN: r172531
This commit is contained in:
parent
5a0f6eba53
commit
deb9642d05
14 changed files with 639 additions and 58 deletions
|
@ -1,3 +1,13 @@
|
|||
2011-04-15 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
|
||||
|
||||
Implement N3271
|
||||
* parser.c (cp_convert_range_for): Split into
|
||||
cp_parser_perform_range_for_lookup.
|
||||
(cp_parser_perform_range_for_lookup): New.
|
||||
(cp_parser_range_for_member_function): New.
|
||||
(cp_parser_for_init_statement): Correct error message.
|
||||
* semantics.c (finish_call_expr): Accept COMPONENT_REF.
|
||||
|
||||
2011-04-14 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* parser.c (cp_parser_objc_protocol_declaration): Updated for
|
||||
|
|
194
gcc/cp/parser.c
194
gcc/cp/parser.c
|
@ -1607,6 +1607,10 @@ static tree cp_parser_c_for
|
|||
(cp_parser *, tree, tree);
|
||||
static tree cp_parser_range_for
|
||||
(cp_parser *, tree, tree, tree);
|
||||
static tree cp_parser_perform_range_for_lookup
|
||||
(tree, tree *, tree *);
|
||||
static tree cp_parser_range_for_member_function
|
||||
(tree, tree);
|
||||
static tree cp_parser_jump_statement
|
||||
(cp_parser *);
|
||||
static void cp_parser_declaration_statement
|
||||
|
@ -8557,14 +8561,20 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl)
|
|||
}
|
||||
|
||||
If RANGE_EXPR is an array:
|
||||
BEGIN_EXPR = __range
|
||||
END_EXPR = __range + ARRAY_SIZE(__range)
|
||||
BEGIN_EXPR = __range
|
||||
END_EXPR = __range + ARRAY_SIZE(__range)
|
||||
Else if RANGE_EXPR has a member 'begin' or 'end':
|
||||
BEGIN_EXPR = __range.begin()
|
||||
END_EXPR = __range.end()
|
||||
Else:
|
||||
BEGIN_EXPR = begin(__range)
|
||||
END_EXPR = end(__range);
|
||||
|
||||
When calling begin()/end() we must use argument dependent
|
||||
lookup, but always considering 'std' as an associated namespace. */
|
||||
If __range has a member 'begin' but not 'end', or vice versa, we must
|
||||
still use the second alternative (it will surely fail, however).
|
||||
When calling begin()/end() in the third alternative we must use
|
||||
argument dependent lookup, but always considering 'std' as an associated
|
||||
namespace. */
|
||||
|
||||
tree
|
||||
cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
|
||||
|
@ -8581,12 +8591,12 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
|
|||
else
|
||||
{
|
||||
/* Find out the type deduced by the declaration
|
||||
* `auto &&__range = range_expr' */
|
||||
`auto &&__range = range_expr'. */
|
||||
range_type = cp_build_reference_type (make_auto (), true);
|
||||
range_type = do_auto_deduction (range_type, range_expr,
|
||||
type_uses_auto (range_type));
|
||||
|
||||
/* Create the __range variable */
|
||||
/* Create the __range variable. */
|
||||
range_temp = build_decl (input_location, VAR_DECL,
|
||||
get_identifier ("__for_range"), range_type);
|
||||
TREE_USED (range_temp) = 1;
|
||||
|
@ -8597,51 +8607,11 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
|
|||
LOOKUP_ONLYCONVERTING);
|
||||
|
||||
range_temp = convert_from_reference (range_temp);
|
||||
|
||||
if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
|
||||
{
|
||||
/* If RANGE_TEMP is an array we will use pointer arithmetic */
|
||||
iter_type = build_pointer_type (TREE_TYPE (TREE_TYPE (range_temp)));
|
||||
begin_expr = range_temp;
|
||||
end_expr
|
||||
= build_binary_op (input_location, PLUS_EXPR,
|
||||
range_temp,
|
||||
array_type_nelts_top (TREE_TYPE (range_temp)),
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If it is not an array, we must call begin(__range)/end__range() */
|
||||
VEC(tree,gc) *vec;
|
||||
|
||||
begin_expr = get_identifier ("begin");
|
||||
vec = make_tree_vector ();
|
||||
VEC_safe_push (tree, gc, vec, range_temp);
|
||||
begin_expr = perform_koenig_lookup (begin_expr, vec,
|
||||
/*include_std=*/true);
|
||||
begin_expr = finish_call_expr (begin_expr, &vec, false, true,
|
||||
tf_warning_or_error);
|
||||
release_tree_vector (vec);
|
||||
|
||||
end_expr = get_identifier ("end");
|
||||
vec = make_tree_vector ();
|
||||
VEC_safe_push (tree, gc, vec, range_temp);
|
||||
end_expr = perform_koenig_lookup (end_expr, vec,
|
||||
/*include_std=*/true);
|
||||
end_expr = finish_call_expr (end_expr, &vec, false, true,
|
||||
tf_warning_or_error);
|
||||
release_tree_vector (vec);
|
||||
|
||||
/* The unqualified type of the __begin and __end temporaries should
|
||||
* be the same as required by the multiple auto declaration */
|
||||
iter_type = cv_unqualified (TREE_TYPE (begin_expr));
|
||||
if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (end_expr))))
|
||||
error ("inconsistent begin/end types in range-based for: %qT and %qT",
|
||||
TREE_TYPE (begin_expr), TREE_TYPE (end_expr));
|
||||
}
|
||||
iter_type = cp_parser_perform_range_for_lookup (range_temp,
|
||||
&begin_expr, &end_expr);
|
||||
}
|
||||
|
||||
/* The new for initialization statement */
|
||||
/* The new for initialization statement. */
|
||||
begin = build_decl (input_location, VAR_DECL,
|
||||
get_identifier ("__for_begin"), iter_type);
|
||||
TREE_USED (begin) = 1;
|
||||
|
@ -8662,18 +8632,18 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
|
|||
|
||||
finish_for_init_stmt (statement);
|
||||
|
||||
/* The new for condition */
|
||||
/* The new for condition. */
|
||||
condition = build_x_binary_op (NE_EXPR,
|
||||
begin, ERROR_MARK,
|
||||
end, ERROR_MARK,
|
||||
NULL, tf_warning_or_error);
|
||||
finish_for_cond (condition, statement);
|
||||
|
||||
/* The new increment expression */
|
||||
/* The new increment expression. */
|
||||
expression = finish_unary_op_expr (PREINCREMENT_EXPR, begin);
|
||||
finish_for_expr (expression, statement);
|
||||
|
||||
/* The declaration is initialized with *__begin inside the loop body */
|
||||
/* The declaration is initialized with *__begin inside the loop body. */
|
||||
cp_finish_decl (range_decl,
|
||||
build_x_indirect_ref (begin, RO_NULL, tf_warning_or_error),
|
||||
/*is_constant_init*/false, NULL_TREE,
|
||||
|
@ -8682,6 +8652,124 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
|
|||
return statement;
|
||||
}
|
||||
|
||||
/* Solves BEGIN_EXPR and END_EXPR as described in cp_convert_range_for.
|
||||
We need to solve both at the same time because the method used
|
||||
depends on the existence of members begin or end.
|
||||
Returns the type deduced for the iterator expression. */
|
||||
|
||||
static tree
|
||||
cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
|
||||
{
|
||||
if (!COMPLETE_TYPE_P (TREE_TYPE (range)))
|
||||
{
|
||||
error ("range-based %<for%> expression of type %qT "
|
||||
"has incomplete type", TREE_TYPE (range));
|
||||
*begin = *end = error_mark_node;
|
||||
return error_mark_node;
|
||||
}
|
||||
if (TREE_CODE (TREE_TYPE (range)) == ARRAY_TYPE)
|
||||
{
|
||||
/* If RANGE is an array, we will use pointer arithmetic. */
|
||||
*begin = range;
|
||||
*end = build_binary_op (input_location, PLUS_EXPR,
|
||||
range,
|
||||
array_type_nelts_top (TREE_TYPE (range)),
|
||||
0);
|
||||
return build_pointer_type (TREE_TYPE (TREE_TYPE (range)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If it is not an array, we must do a bit of magic. */
|
||||
tree id_begin, id_end;
|
||||
tree member_begin, member_end;
|
||||
|
||||
*begin = *end = error_mark_node;
|
||||
|
||||
id_begin = get_identifier ("begin");
|
||||
id_end = get_identifier ("end");
|
||||
member_begin = lookup_member (TREE_TYPE (range), id_begin,
|
||||
/*protect=*/2, /*want_type=*/false);
|
||||
member_end = lookup_member (TREE_TYPE (range), id_end,
|
||||
/*protect=*/2, /*want_type=*/false);
|
||||
|
||||
if (member_begin != NULL_TREE || member_end != NULL_TREE)
|
||||
{
|
||||
/* Use the member functions. */
|
||||
if (member_begin != NULL_TREE)
|
||||
*begin = cp_parser_range_for_member_function (range, id_begin);
|
||||
else
|
||||
error ("range-based %<for%> expression of type %qT has an "
|
||||
"%<end%> member but not a %<begin%>", TREE_TYPE (range));
|
||||
|
||||
if (member_end != NULL_TREE)
|
||||
*end = cp_parser_range_for_member_function (range, id_end);
|
||||
else
|
||||
error ("range-based %<for%> expression of type %qT has a "
|
||||
"%<begin%> member but not an %<end%>", TREE_TYPE (range));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use global functions with ADL. */
|
||||
VEC(tree,gc) *vec;
|
||||
vec = make_tree_vector ();
|
||||
|
||||
VEC_safe_push (tree, gc, vec, range);
|
||||
|
||||
member_begin = perform_koenig_lookup (id_begin, vec,
|
||||
/*include_std=*/true);
|
||||
*begin = finish_call_expr (member_begin, &vec, false, true,
|
||||
tf_warning_or_error);
|
||||
member_end = perform_koenig_lookup (id_end, vec,
|
||||
/*include_std=*/true);
|
||||
*end = finish_call_expr (member_end, &vec, false, true,
|
||||
tf_warning_or_error);
|
||||
|
||||
release_tree_vector (vec);
|
||||
}
|
||||
|
||||
/* Last common checks. */
|
||||
if (*begin == error_mark_node || *end == error_mark_node)
|
||||
{
|
||||
/* If one of the expressions is an error do no more checks. */
|
||||
*begin = *end = error_mark_node;
|
||||
return error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree iter_type = cv_unqualified (TREE_TYPE (*begin));
|
||||
/* The unqualified type of the __begin and __end temporaries should
|
||||
be the same, as required by the multiple auto declaration. */
|
||||
if (!same_type_p (iter_type, cv_unqualified (TREE_TYPE (*end))))
|
||||
error ("inconsistent begin/end types in range-based %<for%> "
|
||||
"statement: %qT and %qT",
|
||||
TREE_TYPE (*begin), TREE_TYPE (*end));
|
||||
return iter_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function for cp_parser_perform_range_for_lookup.
|
||||
Builds a tree for RANGE.IDENTIFIER(). */
|
||||
|
||||
static tree
|
||||
cp_parser_range_for_member_function (tree range, tree identifier)
|
||||
{
|
||||
tree member, res;
|
||||
VEC(tree,gc) *vec;
|
||||
|
||||
member = finish_class_member_access_expr (range, identifier,
|
||||
false, tf_warning_or_error);
|
||||
if (member == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
vec = make_tree_vector ();
|
||||
res = finish_call_expr (member, &vec,
|
||||
/*disallow_virtual=*/false,
|
||||
/*koenig_p=*/false,
|
||||
tf_warning_or_error);
|
||||
release_tree_vector (vec);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Parse an iteration-statement.
|
||||
|
||||
|
@ -8830,7 +8918,7 @@ cp_parser_for_init_statement (cp_parser* parser, tree *decl)
|
|||
if (cxx_dialect < cxx0x)
|
||||
{
|
||||
error_at (cp_lexer_peek_token (parser->lexer)->location,
|
||||
"range-based-for loops are not allowed "
|
||||
"range-based %<for%> loops are not allowed "
|
||||
"in C++98 mode");
|
||||
*decl = error_mark_node;
|
||||
}
|
||||
|
|
|
@ -2074,6 +2074,22 @@ finish_call_expr (tree fn, VEC(tree,gc) **args, bool disallow_virtual,
|
|||
make_args_non_dependent (*args);
|
||||
}
|
||||
|
||||
if (TREE_CODE (fn) == COMPONENT_REF)
|
||||
{
|
||||
tree member = TREE_OPERAND (fn, 1);
|
||||
if (BASELINK_P (member))
|
||||
{
|
||||
tree object = TREE_OPERAND (fn, 0);
|
||||
return build_new_method_call (object, member,
|
||||
args, NULL_TREE,
|
||||
(disallow_virtual
|
||||
? LOOKUP_NORMAL | LOOKUP_NONVIRTUAL
|
||||
: LOOKUP_NORMAL),
|
||||
/*fn_p=*/NULL,
|
||||
complain);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_overloaded_fn (fn))
|
||||
fn = baselink_for_fns (fn);
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
2011-04-15 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/cpp0x/range-for17.C: New.
|
||||
|
||||
2011-04-15 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
|
||||
|
||||
* g++.dg/cpp0x/range-for2.C: Correct for declaration.
|
||||
* g++.dg/cpp0x/range-for3.C: Likewise.
|
||||
* g++.dg/cpp0x/range-for9.C: Correct error message.
|
||||
* g++.dg/cpp0x/range-for11.C: New.
|
||||
* g++.dg/cpp0x/range-for12.C: New.
|
||||
* g++.dg/cpp0x/range-for13.C: New.
|
||||
* g++.dg/cpp0x/range-for14.C: New.
|
||||
* g++.dg/cpp0x/range-for15.C: New.
|
||||
* g++.dg/cpp0x/range-for16.C: New.
|
||||
|
||||
2011-04-15 Tobias Burnus <burnus@net-b.de>
|
||||
|
||||
PR fortran/18918
|
||||
|
|
40
gcc/testsuite/g++.dg/cpp0x/range-for11.C
Normal file
40
gcc/testsuite/g++.dg/cpp0x/range-for11.C
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Test for range-based for loop
|
||||
// Test the loop with a custom iterator
|
||||
// with begin/end as member functions
|
||||
|
||||
// { dg-do compile }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
struct iterator
|
||||
{
|
||||
int x;
|
||||
explicit iterator(int v) :x(v) {}
|
||||
iterator &operator ++() { ++x; return *this; }
|
||||
int operator *() { return x; }
|
||||
bool operator != (const iterator &o) { return x != o.x; }
|
||||
};
|
||||
|
||||
namespace foo
|
||||
{
|
||||
struct container
|
||||
{
|
||||
int min, max;
|
||||
container(int a, int b) :min(a), max(b) {}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return iterator(min);
|
||||
}
|
||||
iterator end()
|
||||
{
|
||||
return iterator(max + 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
foo::container c(1,4);
|
||||
for (int it : c)
|
||||
;
|
||||
}
|
116
gcc/testsuite/g++.dg/cpp0x/range-for12.C
Normal file
116
gcc/testsuite/g++.dg/cpp0x/range-for12.C
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Test for range-based for loop with templates
|
||||
// and begin/end as member functions
|
||||
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
/* Preliminary declarations */
|
||||
namespace pre
|
||||
{
|
||||
struct iterator
|
||||
{
|
||||
int x;
|
||||
explicit iterator (int v) :x(v) {}
|
||||
iterator &operator ++() { ++x; return *this; }
|
||||
int operator *() { return x; }
|
||||
bool operator != (const iterator &o) { return x != o.x; }
|
||||
};
|
||||
|
||||
struct container
|
||||
{
|
||||
int min, max;
|
||||
container(int a, int b) :min(a), max(b) {}
|
||||
iterator begin() const
|
||||
{
|
||||
return iterator(min);
|
||||
}
|
||||
iterator end() const
|
||||
{
|
||||
return iterator(max);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} //namespace pre
|
||||
|
||||
using pre::container;
|
||||
extern "C" void abort(void);
|
||||
|
||||
container run_me_just_once()
|
||||
{
|
||||
static bool run = false;
|
||||
if (run)
|
||||
abort();
|
||||
run = true;
|
||||
return container(1,2);
|
||||
}
|
||||
|
||||
/* Template with dependent expression. */
|
||||
template<typename T> int test1(const T &r)
|
||||
{
|
||||
int t = 0;
|
||||
for (int i : r)
|
||||
t += i;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Template with non-dependent expression and dependent declaration. */
|
||||
template<typename T> int test2(const container &r)
|
||||
{
|
||||
int t = 0;
|
||||
for (T i : r)
|
||||
t += i;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Template with non-dependent expression (array) and dependent declaration. */
|
||||
template<typename T> int test2(const int (&r)[4])
|
||||
{
|
||||
int t = 0;
|
||||
for (T i : r)
|
||||
t += i;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Template with non-dependent expression and auto declaration. */
|
||||
template<typename T> int test3(const container &r)
|
||||
{
|
||||
int t = 0;
|
||||
for (auto i : r)
|
||||
t += i;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Template with non-dependent expression (array) and auto declaration. */
|
||||
template<typename T> int test3(const int (&r)[4])
|
||||
{
|
||||
int t = 0;
|
||||
for (auto i : r)
|
||||
t += i;
|
||||
return t;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
container c(1,5);
|
||||
int a[4] = {5,6,7,8};
|
||||
|
||||
for (auto x : run_me_just_once())
|
||||
;
|
||||
|
||||
if (test1 (c) != 10)
|
||||
abort();
|
||||
if (test1 (a) != 26)
|
||||
abort();
|
||||
|
||||
if (test2<int> (c) != 10)
|
||||
abort();
|
||||
if (test2<int> (a) != 26)
|
||||
abort();
|
||||
|
||||
if (test3<int> (c) != 10)
|
||||
abort();
|
||||
if (test3<int> (a) != 26)
|
||||
abort();
|
||||
return 0;
|
||||
}
|
103
gcc/testsuite/g++.dg/cpp0x/range-for13.C
Normal file
103
gcc/testsuite/g++.dg/cpp0x/range-for13.C
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Test for errors in range-based for loops
|
||||
// with member begin/end
|
||||
|
||||
// { dg-do compile }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
//These should not be used
|
||||
template<typename T> int *begin(T &t)
|
||||
{
|
||||
T::fail;
|
||||
}
|
||||
template<typename T> int *end(T &t)
|
||||
{
|
||||
T::fail;
|
||||
}
|
||||
|
||||
struct container1
|
||||
{
|
||||
int *begin();
|
||||
//no end
|
||||
};
|
||||
|
||||
struct container2
|
||||
{
|
||||
int *end();
|
||||
//no begin
|
||||
};
|
||||
|
||||
struct container3
|
||||
{
|
||||
private:
|
||||
int *begin(); // { dg-error "is private" }
|
||||
int *end(); // { dg-error "is private" }
|
||||
};
|
||||
|
||||
struct container4
|
||||
{
|
||||
int *begin;
|
||||
int *end;
|
||||
};
|
||||
|
||||
struct container5
|
||||
{
|
||||
typedef int *begin;
|
||||
typedef int *end;
|
||||
};
|
||||
|
||||
struct callable
|
||||
{
|
||||
int *operator()();
|
||||
};
|
||||
|
||||
struct container6
|
||||
{
|
||||
callable begin;
|
||||
callable end;
|
||||
};
|
||||
|
||||
struct container7
|
||||
{
|
||||
static callable begin;
|
||||
static callable end;
|
||||
};
|
||||
|
||||
struct container8
|
||||
{
|
||||
static int *begin();
|
||||
int *end();
|
||||
};
|
||||
|
||||
struct private_callable
|
||||
{
|
||||
private:
|
||||
int *operator()(); // { dg-error "is private" }
|
||||
};
|
||||
|
||||
struct container9
|
||||
{
|
||||
private_callable begin;
|
||||
private_callable end;
|
||||
};
|
||||
|
||||
struct container10
|
||||
{
|
||||
typedef int *(*function)();
|
||||
|
||||
function begin;
|
||||
static function end;
|
||||
};
|
||||
|
||||
void test1()
|
||||
{
|
||||
for (int x : container1()); // { dg-error "member but not" }
|
||||
for (int x : container2()); // { dg-error "member but not" }
|
||||
for (int x : container3()); // { dg-error "within this context" }
|
||||
for (int x : container4()); // { dg-error "cannot be used as a function" }
|
||||
for (int x : container5()); // { dg-error "invalid use of" }
|
||||
for (int x : container6());
|
||||
for (int x : container7());
|
||||
for (int x : container8());
|
||||
for (int x : container9()); // { dg-error "within this context" }
|
||||
for (int x : container10());
|
||||
}
|
95
gcc/testsuite/g++.dg/cpp0x/range-for14.C
Normal file
95
gcc/testsuite/g++.dg/cpp0x/range-for14.C
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Test for other range-based for loops with
|
||||
// begin/end member functions
|
||||
|
||||
// { dg-do compile }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
//These should not be used
|
||||
template<typename T> int *begin(T &t)
|
||||
{
|
||||
T::fail;
|
||||
}
|
||||
template<typename T> int *end(T &t)
|
||||
{
|
||||
T::fail;
|
||||
}
|
||||
|
||||
//Test for defaults
|
||||
|
||||
struct default1
|
||||
{
|
||||
int *begin(int x); // { dg-message "note" }
|
||||
int *end();
|
||||
};
|
||||
|
||||
struct default2
|
||||
{
|
||||
int *begin(int x=0);
|
||||
int *end();
|
||||
};
|
||||
|
||||
struct default3
|
||||
{
|
||||
template <typename T> T *begin(); // { dg-message "note" }
|
||||
int *end();
|
||||
};
|
||||
|
||||
struct default4
|
||||
{
|
||||
template <typename T=int> T *begin();
|
||||
int *end();
|
||||
};
|
||||
|
||||
struct default5
|
||||
{
|
||||
template <typename T=int> T *begin(int x=0);
|
||||
int *end();
|
||||
};
|
||||
|
||||
void test1()
|
||||
{
|
||||
for (int x : default1()); // { dg-error "no matching function|note" }
|
||||
for (int x : default2());
|
||||
for (int x : default3()); // { dg-error "no matching function|note" }
|
||||
for (int x : default4());
|
||||
for (int x : default5());
|
||||
}
|
||||
|
||||
//Inheritance tests
|
||||
|
||||
struct base_begin
|
||||
{
|
||||
int *begin(); // { dg-error "" }
|
||||
};
|
||||
|
||||
struct base_end
|
||||
{
|
||||
int *end();
|
||||
};
|
||||
|
||||
struct derived1 : base_begin, base_end
|
||||
{
|
||||
};
|
||||
|
||||
struct base_begin2 : base_begin
|
||||
{
|
||||
};
|
||||
|
||||
struct derived2 : base_begin, base_end, base_begin2 // { dg-warning "" }
|
||||
{
|
||||
};
|
||||
|
||||
struct base_begin3 : virtual base_begin
|
||||
{
|
||||
};
|
||||
|
||||
struct derived3 : virtual base_begin, base_end, base_begin3
|
||||
{
|
||||
};
|
||||
|
||||
void test2()
|
||||
{
|
||||
for (int x : derived1());
|
||||
for (int x : derived2()); // { dg-error "is ambiguous" }
|
||||
for (int x : derived3());
|
||||
}
|
59
gcc/testsuite/g++.dg/cpp0x/range-for15.C
Normal file
59
gcc/testsuite/g++.dg/cpp0x/range-for15.C
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Test for range-based for loop with templates
|
||||
// and begin/end as member (non-)virtual functions
|
||||
|
||||
// { dg-do run }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
unsigned int g;
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual int *begin()
|
||||
{
|
||||
g |= 1;
|
||||
return 0;
|
||||
}
|
||||
int *end()
|
||||
{
|
||||
g |= 2;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct B : A
|
||||
{
|
||||
virtual int *begin()
|
||||
{
|
||||
g |= 4;
|
||||
return 0;
|
||||
}
|
||||
int *end()
|
||||
{
|
||||
g |= 8;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" void abort(void);
|
||||
|
||||
int main ()
|
||||
{
|
||||
A a;
|
||||
B b;
|
||||
A &aa = b;
|
||||
|
||||
g = 0;
|
||||
for (int x : a);
|
||||
if (g != (1 | 2))
|
||||
abort();
|
||||
|
||||
g = 0;
|
||||
for (int x : b);
|
||||
if (g != (4 | 8))
|
||||
abort();
|
||||
|
||||
g = 0;
|
||||
for (int x : aa);
|
||||
if (g != (4 | 2))
|
||||
abort();
|
||||
}
|
21
gcc/testsuite/g++.dg/cpp0x/range-for16.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/range-for16.C
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Test for range-based for loop with arrays of
|
||||
// incomplete type or unknown size
|
||||
|
||||
// { dg-do compile }
|
||||
// { dg-options "-std=c++0x" }
|
||||
|
||||
extern int a[10];
|
||||
extern int b[];
|
||||
|
||||
struct S;
|
||||
extern S c[10];
|
||||
extern S d[];
|
||||
|
||||
void test()
|
||||
{
|
||||
for (int n : a);
|
||||
for (int n : b); // { dg-error "incomplete type" }
|
||||
for (S &n : c); // { dg-error "incomplete type" }
|
||||
for (S &n : d); // { dg-error "incomplete type" }
|
||||
for (int n : *c); // { dg-error "incomplete type" }
|
||||
}
|
17
gcc/testsuite/g++.dg/cpp0x/range-for17.C
Normal file
17
gcc/testsuite/g++.dg/cpp0x/range-for17.C
Normal file
|
@ -0,0 +1,17 @@
|
|||
// { dg-options -std=c++0x }
|
||||
|
||||
extern "C" int printf (const char *, ...);
|
||||
|
||||
enum E { e1, e2, e3, X };
|
||||
E operator*(E e) { return e; }
|
||||
E begin(E e) { return e; }
|
||||
E end(E e) { return X; };
|
||||
E operator++(E& e) { return e = E(e+1); }
|
||||
|
||||
int main()
|
||||
{
|
||||
for (auto e: e1)
|
||||
{
|
||||
printf ("%d ", e);
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
struct iterator
|
||||
{
|
||||
int x;
|
||||
iterator(int v) :x(v) {}
|
||||
explicit iterator(int v) :x(v) {}
|
||||
iterator &operator ++() { ++x; return *this; }
|
||||
int operator *() { return x; }
|
||||
bool operator != (const iterator &o) { return x != o.x; }
|
||||
|
@ -36,6 +36,6 @@ namespace foo
|
|||
int main()
|
||||
{
|
||||
foo::container c(1,4);
|
||||
for (iterator it : c)
|
||||
for (int it : c)
|
||||
;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
struct iterator
|
||||
{
|
||||
int x;
|
||||
iterator(int v) :x(v) {}
|
||||
explicit iterator(int v) :x(v) {}
|
||||
iterator &operator ++() { ++x; return *this; }
|
||||
int operator *() { return x; }
|
||||
bool operator != (const iterator &o) { return x != o.x; }
|
||||
|
@ -36,7 +36,7 @@ namespace std
|
|||
int main()
|
||||
{
|
||||
container c(1,4);
|
||||
for (iterator it : c)
|
||||
for (int it : c)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
void test()
|
||||
{
|
||||
int a[] = {0,1,2};
|
||||
for (int x : a) // { dg-error "range-based-for" }
|
||||
for (int x : a) // { dg-error "range-based 'for'" }
|
||||
;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue