view gcc/testsuite/g++.dg/cpp0x/inh-ctor32.C @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents
children
line wrap: on
line source

// { dg-do compile { target c++11 } }
// Minimized from the testcase for PR c++/88146,
// then turned into multiple variants. 

// We issue an error when calling an inherited ctor with at least one
// argument passed through a varargs ellipsis, if the call is in an
// evaluated context.  Even in nonevaluated contexts, we will
// instantiate constexpr templates (unlike non-constexpr templates),
// which might then issue errors that in nonevlauated contexts
// wouldn't be issued.

// In these variants, the inherited ctor is constexpr, but it's only
// called in unevaluated contexts, so no error is issued.  The
// templateness of the ctor doesn't matter, because the only call that
// passes args through the ellipsis is in a noexcept expr, that is not
// evaluated.  The ctors in derived classes are created and
// instantiated, discarding arguments passed through the ellipsis when
// calling base ctors, but that's not reported: we only report a
// problem when *calling* ctors that behave this way.
namespace unevaled_call {
  namespace no_arg_before_ellipsis {
    namespace without_template {
      struct foo {
	constexpr foo(...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0}));
    }

    namespace with_template {
      struct foo {
	template <typename... T>
	constexpr foo(...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0}));
    }
  }

  namespace one_arg_before_ellipsis {
    namespace without_template {
      struct foo {
	constexpr foo(int, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0,1}));
    }

    namespace with_template {
      struct foo {
	template <typename T>
	constexpr foo(T, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0,1}));
    }
  }
}

// In these variants, the inherited ctor is constexpr, and it's called
// in unevaluated contexts in ways that would otherwise trigger the
// sorry message.  Here we check that the message is not issued at
// those calls, nor at subsequent calls that use the same ctor without
// passing arguments through its ellipsis.  We check that it is issued
// later, when we pass the ctor arguments through the ellipsis.
namespace evaled_bad_call_in_u {
  namespace one_arg_before_ellipsis {
    namespace without_template {
      struct foo {
	constexpr foo(int, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0, 1}));
      bar t(0);
      bar u(0, 1); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
    }

    namespace with_template {
      struct foo {
	template <typename T>
	constexpr foo(T, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0,1}));
      bar t(0);
      bar u(0,1); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
    }
  }

  namespace no_arg_before_ellipsis {
    namespace without_template {
      struct foo {
	constexpr foo(...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0}));
      bar u(0); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
    }

    namespace with_template {
      struct foo {
	template <typename... T>
	constexpr foo(...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	using boo::boo;
      };
      void f() noexcept(noexcept(bar{0}));
      bar u(0); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
    }
  }
}

// Now, instead of instantiating a class that uses a derived ctor, we
// introduce another template ctor that will use the varargs ctor to
// initialize its base class.  The idea is to verify that the error
// message is issued, even if the instantiation occurs in a
// nonevaluated context, e.g., for constexpr templates.  In the
// inherited_derived_ctor, we check that even an inherited ctor of a
// constexpr ctor is instantiated and have an error message issued.
namespace derived_ctor {
  namespace direct_derived_ctor {
    namespace constexpr_noninherited_ctor {
      struct foo {
	template <typename T>
	constexpr foo(T, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	template <typename ...T>
	constexpr bar(T ... args) : boo(args...) {}
      };
      void f() noexcept(noexcept(bar{0,1}));
    }

    namespace no_constexpr_noninherited_ctor {
      struct foo {
	template <typename T>
	constexpr foo(T, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bar : boo {
	template <typename ...T>
	/* constexpr */ bar(T ... args) : boo(args...) {}
      };
      void f() noexcept(noexcept(bar{0,1}));
    }
  }

  namespace inherited_derived_ctor {
    namespace constexpr_noninherited_ctor {
      struct foo {
	template <typename T>
	constexpr foo(T, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bor : boo {
	template <typename ...T>
	constexpr bor(T ... args) : boo(args...) {}
      };
      struct bar : bor {
	using bor::bor;
      };
      void f() noexcept(noexcept(bar{0,1}));
    }

    namespace no_constexpr_noninherited_ctor {
      struct foo {
	template <typename T>
	constexpr foo(T, ...) {}
      };
      struct boo : foo {
	using foo::foo;
      };
      struct bor : boo {
	template <typename ...T>
	/* constexpr */ bor(T ... args) : boo(args...) {}
      };
      struct bar : bor {
	using bor::bor;
      };
      void f() noexcept(noexcept(bar{0,1}));
    }
  }
}