blob: d4deedd82f664a5386896a08200d1ef44eeca41d [file] [log] [blame]
// Copyright (C) 2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
// PR libstdc++/100768 - Range iterator operations should be function objects
#include <iterator>
#include <ranges>
namespace ns1
{
struct R { };
void check_adl(R) { }
}
namespace ns2
{
using ns1::R;
struct A { };
template<typename I>
R advance(I, ...) { return R{}; }
template<typename I>
R distance(I, ...) { return R{}; }
template<typename I>
R next(I, ...) { return R{}; }
template<typename I>
R prev(I, ...) { return R{}; }
}
template<typename T, typename U> struct associated { };
void
test02()
{
// This type has both ns2 and std::ranges as associated namespaces.
using X = associated<ns2::A, std::ranges::dangling>;
X range[1];
X* iter = range;
X* const sentinel = iter + 1;
// [range.iter.op.general] p2 says: "The function templates defined in
// [range.iter.ops] are not found by argument-dependent name lookup."
//
// If we do not meet that requirement then the following will find those
// function templates (because std::ranges is an associated namespace),
// and the calls to check_adl will be ill-formed.
check_adl( advance(iter, 1) );
check_adl( advance(iter, 1, sentinel) );
check_adl( distance(iter, sentinel) );
check_adl( distance(range) );
check_adl( next(iter) );
check_adl( next(iter, 1) );
check_adl( next(iter, sentinel) );
check_adl( next(iter, 1, sentinel) );
check_adl( prev(iter) );
check_adl( prev(iter, 1) );
check_adl( prev(iter, 1, sentinel) );
}
namespace ns3
{
struct A { };
void advance(A*, int) = delete;
void advance(A*, int, A*) = delete;
void distance(A*, A*) = delete;
void distance(A(&)[1]) = delete;
void next(A*) = delete;
void next(A*, int) = delete;
void next(A*, A*) = delete;
void next(A*, int, A*) = delete;
void prev(A*) = delete;
void prev(A*, int) = delete;
void prev(A*, int, A*) = delete;
}
void
test01()
{
ns3::A range[1];
ns3::A* iter = range;
ns3::A* const sentinel = iter + 1;
// [range.iter.op.general] p2 also says: "When found by unqualified name
// lookup for the postfix-expression in a function call, they inhibit
// argument-dependent name lookup."
//
// If we do not meet that requirement then the following will find the
// deleted overloads in namespace ns3 (because it is an associated namespace
// and those functions are exact matches for the arguments).
using namespace std::ranges;
(void) advance(iter, 1);
(void) advance(iter, 3, sentinel);
(void) distance(iter, sentinel);
(void) distance(range);
(void) next(iter);
(void) next(iter, -1);
(void) next(iter, sentinel);
(void) next(iter, 5, sentinel);
(void) prev(iter);
(void) prev(iter, 0);
(void) prev(iter, 0, sentinel);
}