reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
// RUN: %clang_cc1 -std=c++11 -verify %s
//
// Note: [class.inhctor] was removed by P0136R1. This tests the new behavior
// for the wording that used to be there.

template<int> struct X {};

// Constructor characteristics are:
//   - the template parameter list
//   - the parameter-type-list
//   - absence or presence of explicit
//   - absence or presence of constexpr
struct A {
  A(X<0>) {} // expected-note 4{{here}}
  constexpr A(X<1>) {}
  explicit A(X<2>) {} // expected-note 6{{here}}
  explicit constexpr A(X<3>) {} // expected-note 4{{here}}
};

A a0 { X<0>{} };
A a0i = { X<0>{} };
constexpr A a0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr A a0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}

A a1 { X<1>{} };
A a1i = { X<1>{} };
constexpr A a1c { X<1>{} };
constexpr A a1ic = { X<1>{} };

A a2 { X<2>{} };
A a2i = { X<2>{} }; // expected-error {{constructor is explicit}}
constexpr A a2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr A a2ic = { X<2>{} }; // expected-error {{constructor is explicit}}

A a3 { X<3>{} };
A a3i = { X<3>{} }; // expected-error {{constructor is explicit}}
constexpr A a3c { X<3>{} };
constexpr A a3ic = { X<3>{} }; // expected-error {{constructor is explicit}}


struct B : A {
  using A::A;
};

B b0 { X<0>{} };
B b0i = { X<0>{} };
constexpr B b0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr B b0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}

B b1 { X<1>{} };
B b1i = { X<1>{} };
constexpr B b1c { X<1>{} };
constexpr B b1ic = { X<1>{} };

B b2 { X<2>{} };
B b2i = { X<2>{} }; // expected-error {{constructor is explicit}}
constexpr B b2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr B b2ic = { X<2>{} }; // expected-error {{constructor is explicit}}

B b3 { X<3>{} };
B b3i = { X<3>{} }; // expected-error {{constructor is explicit}}
constexpr B b3c { X<3>{} };
constexpr B b3ic = { X<3>{} }; // expected-error {{constructor is explicit}}


// 'constexpr' is OK even if the constructor doesn't obey the constraints.
struct NonLiteral { NonLiteral(); };
struct NonConstexpr { NonConstexpr(); constexpr NonConstexpr(int); };
struct Constexpr { constexpr Constexpr(int) {} };

struct BothNonLiteral : NonLiteral, Constexpr { using Constexpr::Constexpr; }; // expected-note {{base class 'NonLiteral' of non-literal type}}
constexpr BothNonLiteral bothNL{42}; // expected-error {{constexpr variable cannot have non-literal type 'const BothNonLiteral'}}

// FIXME: This diagnostic is not very good. We should explain that the problem is that base class NonConstexpr cannot be initialized.
struct BothNonConstexpr
    : NonConstexpr,
      Constexpr {
  using Constexpr::Constexpr; // expected-note {{here}}
};
constexpr BothNonConstexpr bothNC{42}; // expected-error {{must be initialized by a constant expression}} expected-note {{inherited from base class 'Constexpr'}}


struct ConstexprEval {
  constexpr ConstexprEval(int a, const char *p) : k(p[a]) {}
  char k;
};
struct ConstexprEval2 {
  char k2 = 'x';
};
struct ConstexprEval3 : ConstexprEval, ConstexprEval2 {
  using ConstexprEval::ConstexprEval;
};
constexpr ConstexprEval3 ce{4, "foobar"};
static_assert(ce.k == 'a', "");
static_assert(ce.k2 == 'x', "");


struct TemplateCtors { // expected-note 2{{candidate constructor (the implicit}}
  constexpr TemplateCtors() {} // expected-note {{candidate inherited constructor}}
  template<template<int> class T> TemplateCtors(X<0>, T<0>); // expected-note {{here}} expected-note {{candidate inherited constructor}}
  template<int N> TemplateCtors(X<1>, X<N>); // expected-note {{here}} expected-note {{candidate inherited constructor}}
  template<typename T> TemplateCtors(X<2>, T); // expected-note {{here}} expected-note {{candidate inherited constructor}}

  template<typename T = int> TemplateCtors(int, int = 0, int = 0);
};

struct UsingTemplateCtors : TemplateCtors { // expected-note 2{{candidate constructor (the implicit}}
  using TemplateCtors::TemplateCtors; // expected-note 6{{inherited here}}

  constexpr UsingTemplateCtors(X<0>, X<0>) {} // expected-note {{not viable}}
  constexpr UsingTemplateCtors(X<1>, X<1>) {} // expected-note {{not viable}}
  constexpr UsingTemplateCtors(X<2>, X<2>) {} // expected-note {{not viable}}

  template<int = 0> constexpr UsingTemplateCtors(int) {} // expected-note {{not viable}}
  template<typename T = void> constexpr UsingTemplateCtors(int, int) {} // expected-note {{not viable}}
  template<typename T, typename U> constexpr UsingTemplateCtors(int, int, int) {} // expected-note {{couldn't infer}}
};

template<int> struct Y {};
constexpr UsingTemplateCtors uct1{ X<0>{}, X<0>{} };
constexpr UsingTemplateCtors uct2{ X<0>{}, Y<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr UsingTemplateCtors uct3{ X<1>{}, X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr UsingTemplateCtors uct4{ X<1>{}, X<1>{} };
constexpr UsingTemplateCtors uct5{ X<2>{}, 0 }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
constexpr UsingTemplateCtors uct6{ X<2>{}, X<2>{} };

constexpr UsingTemplateCtors utc7{ 0 }; // ok
constexpr UsingTemplateCtors utc8{ 0, 0 }; // ok
// FIXME: The standard says that UsingTemplateCtors' (int, int, int) constructor
// hides the one from TemplateCtors, even though the template parameter lists
// don't match. It's not clear that that's *really* the intent, and it's not
// what other compilers do.
constexpr UsingTemplateCtors utc9{ 0, 0, 0 }; // expected-error {{no matching constructor}}