// Test case reduced from an experimental std modules implementation.
// Tests that the compiler don't emit confusing error about the ambiguous ctor
// about std::pair.
//
// RUN: rm -fr %t
// RUN: mkdir %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 %t/string.cppm -I%t -emit-module-interface -o %t/std-string.pcm
// RUN: %clang_cc1 -std=c++20 %t/algorithm.cppm -I%t -emit-module-interface -o %t/std-algorithm.pcm
// RUN: %clang_cc1 -std=c++20 %t/Use.cppm -I%t -fprebuilt-module-path=%t -emit-module-interface -verify -o %t/Use.pcm
// Test again with reduced BMI.
// RUN: rm -fr %t
// RUN: mkdir %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 %t/string.cppm -I%t -emit-reduced-module-interface -o %t/std-string.pcm
// RUN: %clang_cc1 -std=c++20 %t/algorithm.cppm -I%t -emit-reduced-module-interface -o %t/std-algorithm.pcm
// RUN: %clang_cc1 -std=c++20 %t/Use.cppm -I%t -fprebuilt-module-path=%t -emit-reduced-module-interface -verify -o %t/Use.pcm
//--- Use.cppm
// expected-no-diagnostics
module;
#include "config.h"
# 3 "pair-unambiguous-ctor.cppm" 1 3
export module std:M;
# 3 "pair-unambiguous-ctor.cppm" 2 3
import :string;
import :algorithm;
auto check() {
return std::string();
}
//--- string.cppm
module;
#include "string.h"
# 28 "pair-unambiguous-ctor.cppm" 1 3
export module std:string;
export namespace std {
using std::string;
}
# 28 "pair-unambiguous-ctor.cppm" 2 3
//--- algorithm.cppm
module;
#include "algorithm.h"
# 38 "pair-unambiguous-ctor.cppm" 1 3
export module std:algorithm;
# 38 "pair-unambiguous-ctor.cppm" 2 3
//--- pair.h
namespace std __attribute__ ((__visibility__ ("default")))
{
typedef long unsigned int size_t;
typedef long int ptrdiff_t;
typedef decltype(nullptr) nullptr_t;
template<typename _Tp, _Tp __v>
struct integral_constant
{
static constexpr _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant<_Tp, __v> type;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
template<typename _Tp, _Tp __v>
constexpr _Tp integral_constant<_Tp, __v>::value;
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template<bool __v>
using __bool_constant = integral_constant<bool, __v>;
template<bool, typename, typename>
struct conditional;
template<bool _Cond, typename _Iftrue, typename _Iffalse>
struct conditional
{ typedef _Iftrue type; };
template<typename _Iftrue, typename _Iffalse>
struct conditional<false, _Iftrue, _Iffalse>
{ typedef _Iffalse type; };
template<bool, typename _Tp = void>
struct enable_if
{ };
template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };
template<typename _Tp, typename... _Args>
struct __is_constructible_impl
: public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
template<typename _Tp, typename... _Args>
struct is_constructible
: public __is_constructible_impl<_Tp, _Args...>
{};
template<typename>
struct __is_void_helper
: public false_type { };
template<>
struct __is_void_helper<void>
: public true_type { };
template<typename _Tp>
struct is_void
: public __is_void_helper<_Tp>::type
{ };
template<typename...>
class tuple;
template<std::size_t...>
struct _Index_tuple;
template <bool, typename _T1, typename _T2>
struct _PCC
{
template <typename _U1, typename _U2>
static constexpr bool _ConstructiblePair()
{
return is_constructible<_T1, const _U1&>::value;
}
};
template<typename _T1, typename _T2>
struct pair
{
typedef _T1 first_type;
typedef _T2 second_type;
_T1 first;
_T2 second;
using _PCCP = _PCC<true, _T1, _T2>;
template<typename _U1 = _T1, typename _U2=_T2, typename
enable_if<_PCCP::template
_ConstructiblePair<_U1, _U2>(),
bool>::type=true>
constexpr pair(const _T1& __a, const _T2& __b)
: first(__a), second(__b) { }
constexpr pair&
operator=(typename conditional<
is_constructible<_T2>::value,
const pair&, nullptr_t>::type __p)
{
first = __p.first;
second = __p.second;
return *this;
}
private:
template<typename... _Args1, std::size_t... _Indexes1,
typename... _Args2, std::size_t... _Indexes2>
constexpr
pair(tuple<_Args1...>&, tuple<_Args2...>&,
_Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
};
template<typename _T1, typename _T2> pair(_T1, _T2) -> pair<_T1, _T2>;
}
//--- string.h
#include "pair.h"
namespace std __attribute__ ((__visibility__ ("default")))
{
class __undefined;
template<typename _Tp>
using __make_not_void
= typename conditional<is_void<_Tp>::value, __undefined, _Tp>::type;
template <typename Ptr>
struct pointer_traits {};
template<typename _Tp>
struct pointer_traits<_Tp*>
{
typedef _Tp* pointer;
typedef _Tp element_type;
static constexpr pointer
pointer_to(__make_not_void<element_type>& __r) noexcept
{ return __builtin_addressof(__r); }
};
template<typename _Tp>
class allocator;
template<typename _Alloc>
struct allocator_traits;
template<typename _Tp>
struct allocator_traits<allocator<_Tp>>
{
using pointer = _Tp*;
};
template<typename _Alloc>
struct __alloc_traits
: std::allocator_traits<_Alloc>
{
typedef std::allocator_traits<_Alloc> _Base_type;
typedef typename _Base_type::pointer pointer;
};
template<class _CharT>
struct char_traits;
template<typename _CharT, typename _Traits = char_traits<_CharT>,
typename _Alloc = allocator<_CharT> >
class basic_string
{
typedef std::__alloc_traits<_Alloc> _Alloc_traits;
public:
typedef typename _Alloc_traits::pointer pointer;
private:
pointer _M_dataplus;
_CharT _M_local_buf[16];
pointer
_M_local_data()
{
return std::pointer_traits<pointer>::pointer_to(*_M_local_buf);
}
public:
basic_string()
: _M_dataplus(_M_local_data())
{ }
};
typedef basic_string<char> string;
}
//--- algorithm.h
#include "pair.h"
namespace std {
struct _Power2_rehash_policy
{
std::pair<bool, std::size_t>
_M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt,
std::size_t __n_ins) noexcept
{
return { false, 0 };
}
};
}
//--- config.h
namespace std
{
typedef __SIZE_TYPE__ size_t;
}