//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03

// <tuple>

// See https://llvm.org/PR20855

#include <tuple>
#include <string>

#include "test_macros.h"

template <class Tp>
struct ConvertsTo {
  using RawTp = typename std::remove_cv< typename std::remove_reference<Tp>::type>::type;

  operator Tp() const {
    return static_cast<Tp>(value);
  }

  mutable RawTp value;
};

struct Base {};
struct Derived : Base {};

template <class T> struct CannotDeduce {
 using type = T;
};

template <class ...Args>
void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {}

void f() {
  // Test that we emit our diagnostic from the library.
  // expected-error@tuple:* 8 {{Attempted construction of reference element binds to a temporary whose lifetime has ended}}

  // Good news everybody! Clang now diagnoses this for us!
  // expected-error@tuple:* 0+ {{reference member '__value_' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}

  {
    F<int, const std::string&>(std::make_tuple(1, "abc")); // expected-note 1 {{requested here}}
  }
  {
    std::tuple<int, const std::string&> t(1, "a"); // expected-note 1 {{requested here}}
  }
  {
    F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc")); // expected-note 1 {{requested here}}
  }
  {
    ConvertsTo<int&> ct;
    std::tuple<const long&, int> t(ct, 42); // expected-note {{requested here}}
  }
  {
    ConvertsTo<int> ct;
    std::tuple<int const&, void*> t(ct, nullptr); // expected-note {{requested here}}
  }
  {
    ConvertsTo<Derived> ct;
    std::tuple<Base const&, int> t(ct, 42); // expected-note {{requested here}}
  }
  {
    std::allocator<int> alloc;
    std::tuple<std::string &&> t2("hello"); // expected-note {{requested here}}
    std::tuple<std::string &&> t3(std::allocator_arg, alloc, "hello"); // expected-note {{requested here}}
  }
}
