summaryrefslogtreecommitdiff
path: root/test/SemaTemplate/dependent-template-recover.cpp
blob: c7e27e8da25f16f74326b625ad2abfb1ea3eeb68 (plain)
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
134
135
136
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T, typename U, int N>
struct X {
  void f(T* t) {
    t->f0<U>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
    t->f0<int>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}

    t->operator+<U const, 1>(1); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}}
    t->f1<int const, 2>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}
    t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}}

    T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
    t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}

    (*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
    (*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
    T::f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
    T::f2<0, int>(0); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}

    T::foo<N < 2 || N >= 4>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}

    // If there are multiple potential template names, pick the one where there
    // is no whitespace between the name and the '<'.
    T::foo<T::bar < 1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
    T::foo < T::bar<1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'bar'}}

    // Prefer to diagnose a missing 'template' keyword rather than finding a non-template name.
    xyz < T::foo < 1 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
    T::foo < xyz < 1 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}

    // ... even if the whitespace suggests the other name is the template name.
    // FIXME: Is this the right heuristic?
    xyz<T::foo < 1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
    T::foo < xyz<1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}

    sizeof T::foo < 123 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
    f(t->foo<1, 2>(), // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
      t->bar<3, 4>()); // expected-error{{missing 'template' keyword prior to dependent template name 'bar'}}

    int arr[] = {
      t->baz<1, 2>(1 + 1), // ok, two comparisons
      t->foo<1, 2>(), // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}
      t->bar<3, 4>()  // FIXME: we don't recover from the previous error so don't diagnose this
    };
  }

  int xyz;
};

template <typename T> void not_missing_template(T t) {
  (T::n < 0) > (
     ) // expected-error {{expected expression}}
    ;

  int a = T::x < 3;
  int b = T::y > (); // expected-error {{expected expression}}

  void c(int = T::x < 3);
  void d(int = T::y > ()); // expected-error {{expected expression}}

  for (int x = t < 3 ? 1 : 2; t > (); ++t) { // expected-error {{expected expression}}
  }

  // FIXME: We shouldn't treat 'T::t' as a potential template-name here,
  // because that would leave a '?' with no matching ':'.
  // We should probably generally treat '?' ... ':' as a bracket-like
  // construct.
  bool k = T::t < 3 ? 1 > () : false; // expected-error {{missing 'template' keyword}} expected-error +{{}} expected-note +{{}}
}

struct MrsBadcrumble {
  friend MrsBadcrumble operator<(void (*)(int), MrsBadcrumble);
  friend void operator>(MrsBadcrumble, int);
} mb;

template<int N, typename T> void f(T t) {
  t.f<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'f'}}
  t.T::f<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'f'}}
  T::g<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}}

  // Note: no diagnostic here, this is actually valid as a comparison between
  // the decayed pointer to Y::g<> and mb!
  T::g<mb>(0);

  // ... but this one must be a template-id.
  T::g<mb, int>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}}
}

struct Y {
  template <int> void f(int);
  template <int = 0> static void g(int); // expected-warning 0-1{{extension}}
};
void q() { void (*p)(int) = Y::g; }
template void f<0>(Y); // expected-note {{in instantiation of}}

namespace PR9401 {
  // From GCC PR c++/45558
  template <typename S, typename T>
  struct C
  {
    template <typename U>
    struct B
    {
      template <typename W>
      struct E
      {
        explicit E(const W &x) : w(x) {}
        const W &w;
      };
    };
  };

  struct F;
  template <typename X>
  struct D
  {
    D() {}
  };

  const D<F> g;
  template <typename S, typename T>
  struct A
  {
    template <typename U>
    struct B : C<S, T>::template B<U>
    {
      typedef typename C<S, T>::template B<U> V;
      static const D<typename V::template E<D<F> > > a;
    };
  };

  template <typename S, typename T>
  template <typename U>
  const D<typename C<S, T>::template B<U>::template E<D<F> > >
  A<S, T>::B<U>::a = typename C<S, T>::template B<U>::template E<D<F> >(g);
}